2013年1月20日 星期日

[CC253x][Z-Stack] OSAL NV System - Item/data Length Limitation

    For some reasons, I have to store bulky data (slightly > 5kB, from ZigBee's aspect), receving from  remote, to NVRAM. In order to minimize the effort, I tried to leverage OSAL_NV API to speedup the work. The related API information can be found at "OS Abstraction Layer Application Programming Interface", SWRA194.pdf.

    By referencing other application using OSAL NV memory API, I added osal_nv_item_init() in my application initialization function. However, it returned NV_OPER_FAILED all the time. I traced the code and found that the error is due to written length limitation of OSAL NV system.


    CC2530 flash memory uses 2k page. Apparently OSAL NV doesn't manipulate data item cross page, i.e. item cannot be stored partially at page 1 and the rest at page 2. Thus, the maximum item size can be stored is 2048(byte) - 8(page header) - 8(item header) = 2032 bytes

Page header @ OSAL_nv.c

typedef struct
{
  uint16 active;
  uint16 inUse;
  uint16 xfer;
  uint16 spare;
} osalNvPgHdr_t;

Item header @ OSAL_nv.c

typedef struct
{
  uint16 id;
  uint16 len;   // Enforce Flash-WORD size on len.
  uint16 chk;   // Byte-wise checksum of the 'len' data bytes of the item.
  uint16 stat;  // Item status.
} osalNvHdr_t;



I am still thinking whether it's better to use OSAL NV API or writing customized helper functions to store my data > 2kB.






2013年1月7日 星期一

[ZigBee][CC2530] [Z-Stack][IAR] Generating Hex File Using Z-Stack for Release

    TI does provide comprehensive documents regarding its products, compared to many other chip vendors. However, too many documents without directory lead us lost ourselves.

    In Z-Stack Samples, we generate .d51 file under "EXE" directory by default. To generate hex file for mass production, I found there is useful introduction at How to configure the IAR EW 8051 to generate a hex file for CC2530 using Z-Stack? (plus link for CC2430/CC2431)



Step 1: Open the Z-stack workspace with IAR and locate the linker file f8w2530.xcl.
The f8w2530.xcl file can be found in the Tools file group in IAR.


  • To avoid change this file back and forth for debug and release, I copied it to the project folder and added to my release configuration (IAR->Project Option->Linker->Config Tab->Linker Configuration File, override default to the new .xcl)
  • at Output Tab of Linker, Click the “Override default” option in the “Output file” box and rename the xxx.a51 to xxx.hex 





Step 2: Include the linker file –M option by including the 3 lines as shown in the figure below.
// Include these two lines when generating a .hex file for banked code model:
-M(CODE)[(_CODEBANK_START+_FIRST_BANK_ADDR)-(_CODEBANK_END+_FIRST_BANK_ADDR)]*\
_NR_OF_BANKS+_FIRST_BANK_ADDR=0x8000

For the rest steps you may follow "How to configure the IAR EW 8051 to generate a hex file for CC2530 using Z-Stack? (plus link for CC2430/CC2431)"


I was using


IAR Assembler for 8051
  8.10.3 (8.10.3.40338)

ZStack-2.5.1a

2013年1月4日 星期五

[ZigBee][CC2530] [Z-Stack] Combining SerialApp and TransmitApp - Multiple Endpoints in One ZigBee Device

    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.