CC2530,zigbee,协议栈,代码集(协议栈操作系统,应用框架层,安全层,地址处理,工程配置)

10 篇文章 1 订阅
8 篇文章 1 订阅

OSAL(协议栈操作系统)

comdef.h


#ifndef COMDEF_H
#define COMDEF_H

#ifdef __cplusplus
extern "C"
{
#endif

/* HAL */
#include "hal_types.h"
#include "hal_defs.h"


#define VOID (void)

#define NULL_OK
#define INP
#define OUTP
#define UNUSED
#define ONLY
#define READONLY
#define SHARED
#define KEEP
#define RELAX


#ifndef false
  #define false 0
#endif

#ifndef true
  #define true 1
#endif

#ifndef CONST
  #define CONST const
#endif

#ifndef GENERIC
  #define GENERIC
#endif

/*** Generic Status Return Values ***/
#define SUCCESS                   0x00
#define FAILURE                   0x01
#define INVALIDPARAMETER          0x02
#define INVALID_TASK              0x03
#define MSG_BUFFER_NOT_AVAIL      0x04
#define INVALID_MSG_POINTER       0x05
#define INVALID_EVENT_ID          0x06
#define INVALID_INTERRUPT_ID      0x07
#define NO_TIMER_AVAIL            0x08
#define NV_ITEM_UNINIT            0x09
#define NV_OPER_FAILED            0x0A
#define INVALID_MEM_SIZE          0x0B
#define NV_BAD_ITEM_LEN           0x0C

// Generic Status return
typedef uint8 Status_t;

// Data types
typedef int32   int24;
typedef uint32  uint24;



#define SYS_EVENT_MSG               0x8000  // A message is waiting event

#define KEY_CHANGE                0xC0    // Key Events

#ifdef __cplusplus
}
#endif

#endif 

OSAL.c

#include <string.h>

#include "comdef.h"
#include "OSAL.h"
#include "OSAL_Tasks.h"
#include "OSAL_Memory.h"
#include "OSAL_PwrMgr.h"
#include "OSAL_Clock.h"

#include "OnBoard.h"

/* HAL */
#include "hal_drivers.h"

#ifdef IAR_ARMCM3_LM
  #include "FreeRTOSConfig.h"
  #include "osal_task.h"
#endif

// Message Pool Definitions
osal_msg_q_t osal_qHead;

// Index of active task
static uint8 activeTaskID = TASK_NO_TASK;

/* very ugly stub so Keil can compile */
#ifdef __KEIL__
char *  itoa ( int value, char * buffer, int radix )
{
  return(buffer);
}
#endif

int osal_strlen( char *pString )
{
  return (int)( strlen( pString ) );
}

void *osal_memcpy( void *dst, const void GENERIC *src, unsigned int len )
{
  uint8 *pDst;
  const uint8 GENERIC *pSrc;

  pSrc = src;
  pDst = dst;

  while ( len-- )
    *pDst++ = *pSrc++;

  return ( pDst );
}

void *osal_revmemcpy( void *dst, const void GENERIC *src, unsigned int len )
{
  uint8 *pDst;
  const uint8 GENERIC *pSrc;

  pSrc = src;
  pSrc += (len-1);
  pDst = dst;

  while ( len-- )
    *pDst++ = *pSrc--;

  return ( pDst );
}


void *osal_memdup( const void GENERIC *src, unsigned int len )
{
  uint8 *pDst;

  pDst = osal_mem_alloc( len );
  if ( pDst )
  {
    VOID osal_memcpy( pDst, src, len );
  }

  return ( (void *)pDst );
}

uint8 osal_memcmp( const void GENERIC *src1, const void GENERIC *src2, unsigned int len )
{
  const uint8 GENERIC *pSrc1;
  const uint8 GENERIC *pSrc2;

  pSrc1 = src1;
  pSrc2 = src2;

  while ( len-- )
  {
    if( *pSrc1++ != *pSrc2++ )
      return FALSE;
  }
  return TRUE;
}


void *osal_memset( void *dest, uint8 value, int len )
{
  return memset( dest, value, len );
}

uint16 osal_build_uint16( uint8 *swapped )
{
  return ( BUILD_UINT16( swapped[0], swapped[1] ) );
}


uint32 osal_build_uint32( uint8 *swapped, uint8 len )
{
  if ( len == 2 )
    return ( BUILD_UINT32( swapped[0], swapped[1], 0L, 0L ) );
  else if ( len == 3 )
    return ( BUILD_UINT32( swapped[0], swapped[1], swapped[2], 0L ) );
  else if ( len == 4 )
    return ( BUILD_UINT32( swapped[0], swapped[1], swapped[2], swapped[3] ) );
  else
    return ( (uint32)swapped[0] );
}

#if !defined ( ZBIT ) && !defined ( ZBIT2 ) && !defined (UBIT)

unsigned char * _ltoa(unsigned long l, unsigned char *buf, unsigned char radix)
{
#if defined( __GNUC__ )
  return ( (char*)ltoa( l, buf, radix ) );
#else
  unsigned char tmp1[10] = "", tmp2[10] = "", tmp3[10] = "";
  unsigned short num1, num2, num3;
  unsigned char i;

  buf[0] = '\0';

  if ( radix == 10 )
  {
    num1 = l % 10000;
    num2 = (l / 10000) % 10000;
    num3 = (unsigned short)(l / 100000000);

    if (num3) _itoa(num3, tmp3, 10);
    if (num2) _itoa(num2, tmp2, 10);
    if (num1) _itoa(num1, tmp1, 10);

    if (num3)
    {
      strcpy((char*)buf, (char const*)tmp3);
      for (i = 0; i < 4 - strlen((char const*)tmp2); i++)
        strcat((char*)buf, "0");
    }
    strcat((char*)buf, (char const*)tmp2);
    if (num3 || num2)
    {
      for (i = 0; i < 4 - strlen((char const*)tmp1); i++)
        strcat((char*)buf, "0");
    }
    strcat((char*)buf, (char const*)tmp1);
    if (!num3 && !num2 && !num1)
      strcpy((char*)buf, "0");
  }
  else if ( radix == 16 )
  {
    num1 = l & 0x0000FFFF;
    num2 = l >> 16;

    if (num2) _itoa(num2, tmp2, 16);
    if (num1) _itoa(num1, tmp1, 16);

    if (num2)
    {
      strcpy((char*)buf,(char const*)tmp2);
      for (i = 0; i < 4 - strlen((char const*)tmp1); i++)
        strcat((char*)buf, "0");
    }
    strcat((char*)buf, (char const*)tmp1);
    if (!num2 && !num1)
      strcpy((char*)buf, "0");
  }
  else
    return NULL;

  return buf;
#endif
}
#endif // !defined(ZBIT) && !defined(ZBIT2)

uint16 osal_rand( void )
{
  return ( Onboard_rand() );
}

uint8 * osal_msg_allocate( uint16 len )
{
  osal_msg_hdr_t *hdr;

  if ( len == 0 )
    return ( NULL );

  hdr = (osal_msg_hdr_t *) osal_mem_alloc( (short)(len + sizeof( osal_msg_hdr_t )) );
  if ( hdr )
  {
    hdr->next = NULL;
    hdr->len = len;
    hdr->dest_id = TASK_NO_TASK;
    return ( (uint8 *) (hdr + 1) );
  }
  else
    return ( NULL );
}

uint8 osal_msg_deallocate( uint8 *msg_ptr )
{
  uint8 *x;

  if ( msg_ptr == NULL )
    return ( INVALID_MSG_POINTER );

  // don't deallocate queued buffer
  if ( OSAL_MSG_ID( msg_ptr ) != TASK_NO_TASK )
    return ( MSG_BUFFER_NOT_AVAIL );

  x = (uint8 *)((uint8 *)msg_ptr - sizeof( osal_msg_hdr_t ));

  osal_mem_free( (void *)x );

  return ( SUCCESS );
}

uint8 osal_msg_send( uint8 destination_task, uint8 *msg_ptr )
{
  if ( msg_ptr == NULL )
    return ( INVALID_MSG_POINTER );

  if ( destination_task >= tasksCnt )
  {
    osal_msg_deallocate( msg_ptr );
    return ( INVALID_TASK );
  }

  // Check the message header
  if ( OSAL_MSG_NEXT( msg_ptr ) != NULL ||
       OSAL_MSG_ID( msg_ptr ) != TASK_NO_TASK )
  {
    osal_msg_deallocate( msg_ptr );
    return ( INVALID_MSG_POINTER );
  }

  OSAL_MSG_ID( msg_ptr ) = destination_task;

  // queue message
  osal_msg_enqueue( &osal_qHead, msg_ptr );

  // Signal the task that a message is waiting
  osal_set_event( destination_task, SYS_EVENT_MSG );

  return ( SUCCESS );
}

uint8 *osal_msg_receive( uint8 task_id )
{
  osal_msg_hdr_t *listHdr;
  osal_msg_hdr_t *prevHdr = NULL;
  osal_msg_hdr_t *foundHdr = NULL;
  halIntState_t   intState;

  // Hold off interrupts
  HAL_ENTER_CRITICAL_SECTION(intState);

  // Point to the top of the queue
  listHdr = osal_qHead;

  // Look through the queue for a message that belongs to the asking task
  while ( listHdr != NULL )
  {
    if ( (listHdr - 1)->dest_id == task_id )
    {
      if ( foundHdr == NULL )
      {
        // Save the first one
        foundHdr = listHdr;
      }
      else
      {
        // Second msg found, stop looking
        break;
      }
    }
    if ( foundHdr == NULL )
    {
      prevHdr = listHdr;
    }
    listHdr = OSAL_MSG_NEXT( listHdr );
  }

  // Is there more than one?
  if ( listHdr != NULL )
  {
    // Yes, Signal the task that a message is waiting
    osal_set_event( task_id, SYS_EVENT_MSG );
  }
  else
  {
    // No more
    osal_clear_event( task_id, SYS_EVENT_MSG );
  }

  // Did we find a message?
  if ( foundHdr != NULL )
  {
    // Take out of the link list
    osal_msg_extract( &osal_qHead, foundHdr, prevHdr );
  }

  // Release interrupts
  HAL_EXIT_CRITICAL_SECTION(intState);

  return ( (uint8*) foundHdr );
}

osal_event_hdr_t *osal_msg_find(uint8 task_id, uint8 event)
{
  osal_msg_hdr_t *pHdr;
  halIntState_t intState;

  HAL_ENTER_CRITICAL_SECTION(intState);  // Hold off interrupts.

  pHdr = osal_qHead;  // Point to the top of the queue.

  // Look through the queue for a message that matches the task_id and event parameters.
  while (pHdr != NULL)
  {
    if (((pHdr-1)->dest_id == task_id) && (((osal_event_hdr_t *)pHdr)->event == event))
    {
      break;
    }

    pHdr = OSAL_MSG_NEXT(pHdr);
  }

  HAL_EXIT_CRITICAL_SECTION(intState);  // Release interrupts.

  return (osal_event_hdr_t *)pHdr;
}

void osal_msg_enqueue( osal_msg_q_t *q_ptr, void *msg_ptr )
{
  void *list;
  halIntState_t intState;

  // Hold off interrupts
  HAL_ENTER_CRITICAL_SECTION(intState);

  OSAL_MSG_NEXT( msg_ptr ) = NULL;
  // If first message in queue
  if ( *q_ptr == NULL )
  {
    *q_ptr = msg_ptr;
  }
  else
  {
    // Find end of queue
    for ( list = *q_ptr; OSAL_MSG_NEXT( list ) != NULL; list = OSAL_MSG_NEXT( list ) );

    // Add message to end of queue
    OSAL_MSG_NEXT( list ) = msg_ptr;
  }

  // Re-enable interrupts
  HAL_EXIT_CRITICAL_SECTION(intState);
}

void *osal_msg_dequeue( osal_msg_q_t *q_ptr )
{
  void *msg_ptr = NULL;
  halIntState_t intState;

  // Hold off interrupts
  HAL_ENTER_CRITICAL_SECTION(intState);

  if ( *q_ptr != NULL )
  {
    // Dequeue message
    msg_ptr = *q_ptr;
    *q_ptr = OSAL_MSG_NEXT( msg_ptr );
    OSAL_MSG_NEXT( msg_ptr ) = NULL;
    OSAL_MSG_ID( msg_ptr ) = TASK_NO_TASK;
  }

  // Re-enable interrupts
  HAL_EXIT_CRITICAL_SECTION(intState);

  return msg_ptr;
}

void osal_msg_push( osal_msg_q_t *q_ptr, void *msg_ptr )
{
  halIntState_t intState;

  // Hold off interrupts
  HAL_ENTER_CRITICAL_SECTION(intState);

  // Push message to head of queue
  OSAL_MSG_NEXT( msg_ptr ) = *q_ptr;
  *q_ptr = msg_ptr;

  // Re-enable interrupts
  HAL_EXIT_CRITICAL_SECTION(intState);
}

void osal_msg_extract( osal_msg_q_t *q_ptr, void *msg_ptr, void *prev_ptr )
{
  halIntState_t intState;

  // Hold off interrupts
  HAL_ENTER_CRITICAL_SECTION(intState);

  if ( msg_ptr == *q_ptr )
  {
    // remove from first
    *q_ptr = OSAL_MSG_NEXT( msg_ptr );
  }
  else
  {
    // remove from middle
    OSAL_MSG_NEXT( prev_ptr ) = OSAL_MSG_NEXT( msg_ptr );
  }
  OSAL_MSG_NEXT( msg_ptr ) = NULL;
  OSAL_MSG_ID( msg_ptr ) = TASK_NO_TASK;

  // Re-enable interrupts
  HAL_EXIT_CRITICAL_SECTION(intState);
}

uint8 osal_msg_enqueue_max( osal_msg_q_t *q_ptr, void *msg_ptr, uint8 max )
{
  void *list;
  uint8 ret = FALSE;
  halIntState_t intState;

  // Hold off interrupts
  HAL_ENTER_CRITICAL_SECTION(intState);

  // If first message in queue
  if ( *q_ptr == NULL )
  {
    *q_ptr = msg_ptr;
    ret = TRUE;
  }
  else
  {
    // Find end of queue or max
    list = *q_ptr;
    max--;
    while ( (OSAL_MSG_NEXT( list ) != NULL) && (max > 0) )
    {
      list = OSAL_MSG_NEXT( list );
      max--;
    }

    // Add message to end of queue if max not reached
    if ( max != 0 )
    {
      OSAL_MSG_NEXT( list ) = msg_ptr;
      ret = TRUE;
    }
  }

  // Re-enable interrupts
  HAL_EXIT_CRITICAL_SECTION(intState);

  return ret;
}

uint8 osal_set_event( uint8 task_id, uint16 event_flag )
{
  if ( task_id < tasksCnt )
  {
    halIntState_t   intState;
    HAL_ENTER_CRITICAL_SECTION(intState);    // Hold off interrupts
    tasksEvents[task_id] |= event_flag;  // Stuff the event bit(s)
    HAL_EXIT_CRITICAL_SECTION(intState);     // Release interrupts
    return ( SUCCESS );
  }
   else
  {
    return ( INVALID_TASK );
  }
}

uint8 osal_clear_event( uint8 task_id, uint16 event_flag )
{
  if ( task_id < tasksCnt )
  {
    halIntState_t   intState;
    HAL_ENTER_CRITICAL_SECTION(intState);    // Hold off interrupts
    tasksEvents[task_id] &= ~(event_flag);   // Clear the event bit(s)
    HAL_EXIT_CRITICAL_SECTION(intState);     // Release interrupts
    return ( SUCCESS );
  }
   else
  {
    return ( INVALID_TASK );
  }
}

uint8 osal_isr_register( uint8 interrupt_id, void (*isr_ptr)( uint8* ) )
{
  // Remove these statements when functionality is complete
  (void)interrupt_id;
  (void)isr_ptr;
  return ( SUCCESS );
}

uint8 osal_int_enable( uint8 interrupt_id )
{

  if ( interrupt_id == INTS_ALL )
  {
    HAL_ENABLE_INTERRUPTS();
    return ( SUCCESS );
  }
  else
  {
    return ( INVALID_INTERRUPT_ID );
  }
}

uint8 osal_int_disable( uint8 interrupt_id )
{

  if ( interrupt_id == INTS_ALL )
  {
    HAL_DISABLE_INTERRUPTS();
    return ( SUCCESS );
  }
  else
  {
    return ( INVALID_INTERRUPT_ID );
  }
}

uint8 osal_init_system( void )
{
  // Initialize the Memory Allocation System
  osal_mem_init();

  // Initialize the message queue
  osal_qHead = NULL;

  // Initialize the timers
  osalTimerInit();

  // Initialize the Power Management System
  osal_pwrmgr_init();

  // Initialize the system tasks.
  osalInitTasks();

  // Setup efficient search for the first free block of heap.
  osal_mem_kick();

  return ( SUCCESS );
}

void osal_start_system( void )
{
#if !defined ( ZBIT ) && !defined ( UBIT )
  for(;;)  // Forever Loop
#endif
  {
    osal_run_system();
  }
}

void osal_run_system( void )
{
  uint8 idx = 0;

  osalTimeUpdate();
  Hal_ProcessPoll();

  do {
    if (tasksEvents[idx])  // Task is highest priority that is ready.
    {
      break;
    }
  } while (++idx < tasksCnt);

  if (idx < tasksCnt)
  {
    uint16 events;
    halIntState_t intState;

    HAL_ENTER_CRITICAL_SECTION(intState);
    events = tasksEvents[idx];
    tasksEvents[idx] = 0;  // Clear the Events for this task.
    HAL_EXIT_CRITICAL_SECTION(intState);

    activeTaskID = idx;
    events = (tasksArr[idx])( idx, events );
    activeTaskID = TASK_NO_TASK;

    HAL_ENTER_CRITICAL_SECTION(intState);
    tasksEvents[idx] |= events;  // Add back unprocessed events to the current task.
    HAL_EXIT_CRITICAL_SECTION(intState);
  }
#if defined( POWER_SAVING )
  else  // Complete pass through all task events with no activity?
  {
    osal_pwrmgr_powerconserve();  // Put the processor/system into sleep
  }
#endif

  /* Yield in case cooperative scheduling is being used. */
#if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)
  {
    osal_task_yield();
  }
#endif
}

/
uint8* osal_buffer_uint32( uint8 *buf, uint32 val )
{
  *buf++ = BREAK_UINT32( val, 0 );
  *buf++ = BREAK_UINT32( val, 1 );
  *buf++ = BREAK_UINT32( val, 2 );
  *buf++ = BREAK_UINT32( val, 3 );

  return buf;
}

uint8* osal_buffer_uint24( uint8 *buf, uint24 val )
{
  *buf++ = BREAK_UINT32( val, 0 );
  *buf++ = BREAK_UINT32( val, 1 );
  *buf++ = BREAK_UINT32( val, 2 );

  return buf;
}

uint8 osal_isbufset( uint8 *buf, uint8 val, uint8 len )
{
  uint8 x;

  if ( buf == NULL )
  {
    return ( FALSE );
  }

  for ( x = 0; x < len; x++ )
  {
    // Check for non-initialized value
    if ( buf[x] != val )
    {
      return ( FALSE );
    }
  }
  return ( TRUE );
}

uint8 osal_self( void )
{
  return ( activeTaskID );
}

OSAL.h

#ifndef OSAL_H
#define OSAL_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "comdef.h"
#include "OSAL_Memory.h"
#include "OSAL_Timers.h"

#if ( UINT_MAX == 65535 ) /* 8-bit and 16-bit devices */
  #define osal_offsetof(type, member) ((uint16) &(((type *) 0)->member))
#else /* 32-bit devices */
  #define osal_offsetof(type, member) ((uint32) &(((type *) 0)->member))
#endif

#define OSAL_MSG_NEXT(msg_ptr)      ((osal_msg_hdr_t *) (msg_ptr) - 1)->next

#define OSAL_MSG_Q_INIT(q_ptr)      *(q_ptr) = NULL

#define OSAL_MSG_Q_EMPTY(q_ptr)     (*(q_ptr) == NULL)

#define OSAL_MSG_Q_HEAD(q_ptr)      (*(q_ptr))

#define OSAL_MSG_LEN(msg_ptr)      ((osal_msg_hdr_t *) (msg_ptr) - 1)->len

#define OSAL_MSG_ID(msg_ptr)      ((osal_msg_hdr_t *) (msg_ptr) - 1)->dest_id

/*** Interrupts ***/
#define INTS_ALL    0xFF

typedef struct
{
  void   *next;
  uint16 len;
  uint8  dest_id;
} osal_msg_hdr_t;

typedef struct
{
  uint8  event;
  uint8  status;
} osal_event_hdr_t;

typedef void * osal_msg_q_t;


  extern uint8 * osal_msg_allocate(uint16 len );

  extern uint8 osal_msg_deallocate( uint8 *msg_ptr );

  extern uint8 osal_msg_send( uint8 destination_task, uint8 *msg_ptr );

  extern uint8 *osal_msg_receive( uint8 task_id );

  extern osal_event_hdr_t *osal_msg_find(uint8 task_id, uint8 event);

  extern void osal_msg_enqueue( osal_msg_q_t *q_ptr, void *msg_ptr );

  extern uint8 osal_msg_enqueue_max( osal_msg_q_t *q_ptr, void *msg_ptr, uint8 max );

  extern void *osal_msg_dequeue( osal_msg_q_t *q_ptr );

  extern void osal_msg_push( osal_msg_q_t *q_ptr, void *msg_ptr );

  extern void osal_msg_extract( osal_msg_q_t *q_ptr, void *msg_ptr, void *prev_ptr );

  extern uint8 osal_set_event( uint8 task_id, uint16 event_flag );

  extern uint8 osal_clear_event( uint8 task_id, uint16 event_flag );

  extern uint8 osal_isr_register( uint8 interrupt_id, void (*isr_ptr)( uint8* ) );


  extern uint8 osal_int_enable( uint8 interrupt_id );

  extern uint8 osal_int_disable( uint8 interrupt_id );


  extern uint8 osal_init_system( void );

#if defined (ZBIT)
  extern __declspec(dllexport)  void osal_start_system( void );
#else
  extern void osal_start_system( void );
#endif

  extern void osal_run_system( void );

  extern uint8 osal_self( void );


  extern int osal_strlen( char *pString );

  extern void *osal_memcpy( void*, const void GENERIC *, unsigned int );
  extern void *osal_memdup( const void GENERIC *src, unsigned int len );

  extern void *osal_revmemcpy( void*, const void GENERIC *, unsigned int );

  extern uint8 osal_memcmp( const void GENERIC *src1, const void GENERIC *src2, unsigned int len );

  extern void *osal_memset( void *dest, uint8 value, int len );

  extern uint16 osal_build_uint16( uint8 *swapped );

  extern uint32 osal_build_uint32( uint8 *swapped, uint8 len );

  #if !defined ( ZBIT ) && !defined ( ZBIT2 ) && !defined (UBIT)
    extern uint8 *_ltoa( uint32 l, uint8 * buf, uint8 radix );
  #endif

  extern uint16 osal_rand( void );

  extern uint8* osal_buffer_uint32( uint8 *buf, uint32 val );

  extern uint8* osal_buffer_uint24( uint8 *buf, uint24 val );

  extern uint8 osal_isbufset( uint8 *buf, uint8 val, uint8 len );


#ifdef __cplusplus
}
#endif

#endif

OSAL_Clock.c

#include "comdef.h"
#include "OnBoard.h"
#include "OSAL.h"
#include "OSAL_Clock.h"

#define	YearLength(yr)	((uint16)(IsLeapYear(yr) ? 366 : 365))


#define	BEGYEAR  2000     //  UTC started at 00:00:00 January 1, 2000

#define	DAY      86400UL  // 24 hours * 60 minutes * 60 seconds

extern uint32 macMcuPrecisionCount(void);

#if (defined HAL_MCU_CC2430) || (defined HAL_MCU_CC2530) || (defined HAL_MCU_CC2533)

  extern __near_func uint32 osalMcuDivide31By16To16( uint32 dividend, uint16 divisor );

  #define CONVERT_320US_TO_MS_ELAPSED_REMAINDER( x, y, z ) st( \
                                                               \
    /* The 16 bit quotient is in MSW and */                    \
    /* the 16 bit remainder is in LSW. */                      \
    x = osalMcuDivide31By16To16( x, 25 );                      \
                                                               \
    /* Add quotient to y */                                    \
    y += (x >> 16);                                            \
                                                               \
    /* Copy remainder to z */                                  \
    z = (uint16)(x & 0x0FFFF);                                 \
  )

#else /* (defined HAL_MCU_CC2430) || (defined HAL_MCU_CC2530) || (defined HAL_MCU_CC2533) */

  #define CONVERT_320US_TO_MS_ELAPSED_REMAINDER( x, y, z ) st( \
    y += x / 25;                                               \
    z = x % 25;                                                \
  )

#endif /* (defined HAL_MCU_CC2430) || (defined HAL_MCU_CC2530) || (defined HAL_MCU_CC2533) */

static uint32 previousMacTimerTick = 0;
static uint16 remUsTicks = 0;
static uint16 timeMSec = 0;

// number of seconds since 0 hrs, 0 minutes, 0 seconds, on the
// 1st of January 2000 UTC
UTCTime OSAL_timeSeconds = 0;

static uint8 monthLength( uint8 lpyr, uint8 mon );

static void osalClockUpdate( uint16 elapsedMSec );

void osalTimeUpdate( void )
{
  halIntState_t intState;
  uint32 tmp;
  uint32 ticks320us;
  uint16 elapsedMSec = 0;

  HAL_ENTER_CRITICAL_SECTION(intState);
  // Get the free-running count of 320us timer ticks
  tmp = macMcuPrecisionCount();
  HAL_EXIT_CRITICAL_SECTION(intState);
  
  if ( tmp != previousMacTimerTick )
  {
    // Calculate the elapsed ticks of the free-running timer.
    ticks320us = (tmp - previousMacTimerTick) & 0xffffffffu;

    // Store the MAC Timer tick count for the next time through this function.
    previousMacTimerTick = tmp;
    
    // update converted number with remaining ticks from loop and the
    // accumulated remainder from loop
    tmp = (ticks320us * 8) + remUsTicks;

    // Convert the 320 us ticks into milliseconds and a remainder
    CONVERT_320US_TO_MS_ELAPSED_REMAINDER( tmp, elapsedMSec, remUsTicks );

    // Update OSAL Clock and Timers
    if ( elapsedMSec )
    {
      osalClockUpdate( elapsedMSec );
      osalTimerUpdate( elapsedMSec );
    }
  }
}

static void osalClockUpdate( uint16 elapsedMSec )
{
  // Add elapsed milliseconds to the saved millisecond portion of time
  timeMSec += elapsedMSec;

  // Roll up milliseconds to the number of seconds
  if ( timeMSec >= 1000 )
  {
    OSAL_timeSeconds += timeMSec / 1000;
    timeMSec = timeMSec % 1000;
  }
}

void osal_setClock( UTCTime newTime )
{
  OSAL_timeSeconds = newTime;
}

UTCTime osal_getClock( void )
{
  return ( OSAL_timeSeconds );
}

void osal_ConvertUTCTime( UTCTimeStruct *tm, UTCTime secTime )
{
  // calculate the time less than a day - hours, minutes, seconds
  {
    uint32 day = secTime % DAY;
    tm->seconds = day % 60UL;
    tm->minutes = (day % 3600UL) / 60UL;
    tm->hour = day / 3600UL;
  }

  // Fill in the calendar - day, month, year
  {
    uint16 numDays = secTime / DAY;
    tm->year = BEGYEAR;
    while ( numDays >= YearLength( tm->year ) )
    {
      numDays -= YearLength( tm->year );
      tm->year++;
    }

    tm->month = 0;
    while ( numDays >= monthLength( IsLeapYear( tm->year ), tm->month ) )
    {
      numDays -= monthLength( IsLeapYear( tm->year ), tm->month );
      tm->month++;
    }

    tm->day = numDays;
  }
}

static uint8 monthLength( uint8 lpyr, uint8 mon )
{
  uint8 days = 31;

	if ( mon == 1 ) // feb
  {
		days = ( 28 + lpyr );
  }
  else
  {
    if ( mon > 6 ) // aug-dec
    {
      mon--;
    }

    if ( mon & 1 )
    {
      days = 30;
    }
  }

	return ( days );
}

UTCTime osal_ConvertUTCSecs( UTCTimeStruct *tm )
{
  uint32 seconds;

  /* Seconds for the partial day */
  seconds = (((tm->hour * 60UL) + tm->minutes) * 60UL) + tm->seconds;

  /* Account for previous complete days */
  {
    /* Start with complete days in current month */
    uint16 days = tm->day;

    /* Next, complete months in current year */
    {
      int8 month = tm->month;
      while ( --month >= 0 )
      {
        days += monthLength( IsLeapYear( tm->year ), month );
      }
    }

    /* Next, complete years before current year */
    {
      uint16 year = tm->year;
      while ( --year >= BEGYEAR )
      {
        days += YearLength( year );
      }
    }

    /* Add total seconds before partial day */
    seconds += (days * DAY);
  }

  return ( seconds );
}

OSAL_Clock.h

#ifndef OSAL_CLOCK_H
#define OSAL_CLOCK_H

#ifdef __cplusplus
extern "C"
{
#endif

#define	IsLeapYear(yr)	(!((yr) % 400) || (((yr) % 100) && !((yr) % 4)))

// number of seconds since 0 hrs, 0 minutes, 0 seconds, on the
// 1st of January 2000 UTC
typedef uint32 UTCTime;

// To be used with
typedef struct
{
  uint8 seconds;  // 0-59
  uint8 minutes;  // 0-59
  uint8 hour;     // 0-23
  uint8 day;      // 0-30
  uint8 month;    // 0-11
  uint16 year;    // 2000+
} UTCTimeStruct;


  extern void osalTimeUpdate( void );

  extern void osal_setClock( UTCTime newTime );

  extern UTCTime osal_getClock( void );

  extern void osal_ConvertUTCTime( UTCTimeStruct *tm, UTCTime secTime );

  extern UTCTime osal_ConvertUTCSecs( UTCTimeStruct *tm );


#ifdef __cplusplus
}
#endif

#endif /* OSAL_CLOCK_H */

OSAL_Math.s51

 MODULE   OSAL_Math.s51

  PUBLIC   osalMcuDivide31By16To16
  FUNCTION osalMcuDivide31By16To16,0201H

  EXTERN   ?XSP

  RSEG DATA_Z:DATA:NOROOT(0)
savedR6:
  DS 1
savedR7:
  DS 1
savedRemHi:
  DS 1
savedRemLow:
  DS 1
savedDPH:
  DS 1
savedDPL:
  DS 1

  RSEG NEAR_CODE:CODE:NOROOT(2)
osalMcuDivide31By16To16:

#ifdef DEBUG_GPIO
  //SETB  P0.1
#endif

  // initialize loop counter
  MOV   B,#16

  //  save preserved registers R6 and R7
  MOV   savedR6,R6
  MOV   savedR7,R7

  // save DPTR (which ever one is currently selected)
  MOV   savedDPL,DPL
  MOV   savedDPH,DPH

  // get divisor from the XDATA stack
  MOV   DPL,?XSP
  MOV   DPH,?XSP+1
  MOVX  A,@DPTR
  XCH   A,R6
  INC   DPTR
  MOVX  A,@DPTR
  XCH   A,R7

  // restore DPTR
  MOV   DPL,savedDPL
  MOV   DPH,savedDPH

  // move lower dividend R3:R2 to R1:R0
  MOV   A,R3
  XCH   A,R1
  MOV   A,R2
  XCH   A,R0
  // move upper dividend R5:R4 to what will be the remainder R3:R2
  MOV   A,R5
  XCH   A,R3
  MOV   A,R4
  XCH   A,R2

TopOfLoop:
  // Step 1: Shift dividend and remainder left, feeding dividend into remainder.
  CLR   C
  MOV   A,R0
  RLC   A
  XCH   A,R0
  MOV   A,R1
  RLC   A
  XCH   A,R1
  MOV   A,R2
  RLC   A
  XCH   A,R2
  MOV   A,R3
  RLC   A
  XCH   A,R3

  // Step 2: Subtract divisor from remainder. If there is a borrow, then restore
  //         the remainder.
  CLR   C
  MOV   A,R2
  SUBB  A,R6
  MOV   savedRemLow,A   ; save remainder in case it needs to be restored
  MOV   A,R3
  SUBB  A,R7
  MOV   savedRemHi,A    ; save remainder in case it needs to be restored

  // Step 3: Shift quotient left, feeding complement of borrow bit
  //         Note: Remainder is left unchanged if there was a borrow.
  CPL   C
  JNC   ShiftQuotient
  //
  MOV   R3,savedRemHi
  MOV   R2,savedRemLow

ShiftQuotient:
  MOV   A,R4
  RLC   A
  XCH   A,R4
  MOV   A,R5
  RLC   A
  XCH   A,R5

  // Step 4: Decrement count and loop if not zero.
  DJNZ  B,TopOfLoop

  // restore R6 and R7
  MOV   R6,savedR6
  MOV   R7,savedR7

#ifdef DEBUG_GPIO
  //CLR   P0.1
#endif

  RET

  END

OSAL_Memory.c

#include "comdef.h"
#include "OSAL.h"
#include "OSAL_Memory.h"
#include "OnBoard.h"
#include "hal_assert.h"

#define OSALMEM_IN_USE             0x8000
#if (MAXMEMHEAP & OSALMEM_IN_USE)
#error MAXMEMHEAP is too big to manage!
#endif

#define OSALMEM_HDRSZ              sizeof(osalMemHdr_t)

// Round a value up to the ceiling of OSALMEM_HDRSZ for critical dependencies on even multiples.
#define OSALMEM_ROUND(X)       ((((X) + OSALMEM_HDRSZ - 1) / OSALMEM_HDRSZ) * OSALMEM_HDRSZ)

/* Minimum wasted bytes to justify splitting a block before allocation.
 * Adjust accordingly to attempt to balance the tradeoff of wasted space and runtime throughput
 * spent splitting blocks into sizes that may not be practically usable when sandwiched between
 * two blocks in use (and thereby not able to be coalesced.)
 * Ensure that this size is an even multiple of OSALMEM_HDRSZ.
 */
#if !defined OSALMEM_MIN_BLKSZ
#define OSALMEM_MIN_BLKSZ         (OSALMEM_ROUND((OSALMEM_HDRSZ * 2)))
#endif

#if !defined OSALMEM_LL_BLKSZ
#if defined NONWK
#define OSALMEM_LL_BLKSZ          (OSALMEM_ROUND(6) + (1 * OSALMEM_HDRSZ))
#else
/*
 * Profiling the sample apps with default settings shows the following long-lived allocations
 * which should live at the bottom of the small-block bucket so that they are never iterated over
 * by osal_mem_alloc/free(), nor ever considered for coalescing, etc. This saves significant
 * run-time throughput (on 8051 SOC if not also MSP). This is dynamic "dead space" and is not
 * available to the small-block bucket heap.
 *
 * Adjust this size accordingly to accomodate application-specific changes including changing the
 * size of long-lived objects profiled by sample apps and long-lived objects added by application.
 */
#if defined ZCL_KEY_ESTABLISH     // Attempt to capture worst-case for SE sample apps.
#define OSALMEM_LL_BLKSZ          (OSALMEM_ROUND(526) + (32 * OSALMEM_HDRSZ))
#elif defined TC_LINKKEY_JOIN
#define OSALMEM_LL_BLKSZ          (OSALMEM_ROUND(454) + (21 * OSALMEM_HDRSZ))
#elif ((defined SECURE) && (SECURE != 0))
#define OSALMEM_LL_BLKSZ          (OSALMEM_ROUND(418) + (19 * OSALMEM_HDRSZ))
#else
#define OSALMEM_LL_BLKSZ          (OSALMEM_ROUND(417) + (19 * OSALMEM_HDRSZ))
#endif
#endif
#endif

/* Adjust accordingly to attempt to accomodate the block sizes of the vast majority of
 * very high frequency allocations/frees by profiling the system runtime.
 * This default of 16 accomodates the OSAL timers block, osalTimerRec_t, and many others.
 * Ensure that this size is an even multiple of OSALMEM_MIN_BLKSZ for run-time efficiency.
 */
#if !defined OSALMEM_SMALL_BLKSZ
#define OSALMEM_SMALL_BLKSZ       (OSALMEM_ROUND(16))
#endif
#if !defined OSALMEM_SMALL_BLKCNT
#define OSALMEM_SMALL_BLKCNT       8
#endif

/*
 * These numbers setup the size of the small-block bucket which is reserved at the front of the
 * heap for allocations of OSALMEM_SMALL_BLKSZ or smaller.
 */

// Size of the heap bucket reserved for small block-sized allocations.
// Adjust accordingly to attempt to accomodate the vast majority of very high frequency operations.
#define OSALMEM_SMALLBLK_BUCKET  ((OSALMEM_SMALL_BLKSZ * OSALMEM_SMALL_BLKCNT) + OSALMEM_LL_BLKSZ)
// Index of the first available osalMemHdr_t after the small-block heap which will be set in-use in
// order to prevent the small-block bucket from being coalesced with the wilderness.
#define OSALMEM_SMALLBLK_HDRCNT   (OSALMEM_SMALLBLK_BUCKET / OSALMEM_HDRSZ)
// Index of the first available osalMemHdr_t after the small-block heap which will be set in-use in
#define OSALMEM_BIGBLK_IDX        (OSALMEM_SMALLBLK_HDRCNT + 1)
// The size of the wilderness after losing the small-block heap, the wasted header to block the
// small-block heap from being coalesced, and the wasted header to mark the end of the heap.
#define OSALMEM_BIGBLK_SZ         (MAXMEMHEAP - OSALMEM_SMALLBLK_BUCKET - OSALMEM_HDRSZ*2)
// Index of the last available osalMemHdr_t at the end of the heap which will be set to zero for
// fast comparisons with zero to determine the end of the heap.
#define OSALMEM_LASTBLK_IDX      ((MAXMEMHEAP / OSALMEM_HDRSZ) - 1)

// For information about memory profiling, refer to SWRA204 "Heap Memory Management", section 1.5.
#if !defined OSALMEM_PROFILER
#define OSALMEM_PROFILER           FALSE  // Enable/disable the memory usage profiling buckets.
#endif
#if !defined OSALMEM_PROFILER_LL
#define OSALMEM_PROFILER_LL        FALSE  // Special profiling of the Long-Lived bucket.
#endif

#if OSALMEM_PROFILER
#define OSALMEM_INIT              'X'
#define OSALMEM_ALOC              'A'
#define OSALMEM_REIN              'F'
#endif

typedef struct {
  // The 15 LSB's of 'val' indicate the total item size, including the header, in 8-bit bytes.
  unsigned len : 15;
  // The 1 MSB of 'val' is used as a boolean to indicate in-use or freed.
  unsigned inUse : 1;
} osalMemHdrHdr_t;

typedef union {
  /* Dummy variable so compiler forces structure to alignment of largest element while not wasting
   * space on targets when the halDataAlign_t is smaller than a UINT16.
   */
  halDataAlign_t alignDummy;
  uint16 val;
  osalMemHdrHdr_t hdr;
} osalMemHdr_t;

static __no_init osalMemHdr_t theHeap[MAXMEMHEAP / OSALMEM_HDRSZ];
static __no_init osalMemHdr_t *ff1;  // First free block in the small-block bucket.

static uint8 osalMemStat;            // Discrete status flags: 0x01 = kicked.

#if OSALMEM_METRICS
static uint16 blkMax;  // Max cnt of all blocks ever seen at once.
static uint16 blkCnt;  // Current cnt of all blocks.
static uint16 blkFree; // Current cnt of free blocks.
static uint16 memAlo;  // Current total memory allocated.
static uint16 memMax;  // Max total memory ever allocated at once.
#endif

#if OSALMEM_PROFILER
#define OSALMEM_PROMAX  8
/* The profiling buckets must differ by at least OSALMEM_MIN_BLKSZ; the
 * last bucket must equal the max alloc size. Set the bucket sizes to
 * whatever sizes necessary to show how your application is using memory.
 */
static uint16 proCnt[OSALMEM_PROMAX] = {
OSALMEM_SMALL_BLKSZ, 48, 112, 176, 192, 224, 256, 65535 };
static uint16 proCur[OSALMEM_PROMAX] = { 0 };
static uint16 proMax[OSALMEM_PROMAX] = { 0 };
static uint16 proTot[OSALMEM_PROMAX] = { 0 };
static uint16 proSmallBlkMiss;
#endif


#ifdef DPRINTF_HEAPTRACE
extern int dprintf(const char *fmt, ...);
#endif /* DPRINTF_HEAPTRACE */

void osal_mem_init(void)
{
  HAL_ASSERT(((OSALMEM_MIN_BLKSZ % OSALMEM_HDRSZ) == 0));
  HAL_ASSERT(((OSALMEM_LL_BLKSZ % OSALMEM_HDRSZ) == 0));
  HAL_ASSERT(((OSALMEM_SMALL_BLKSZ % OSALMEM_HDRSZ) == 0));

#if OSALMEM_PROFILER
  (void)osal_memset(theHeap, OSALMEM_INIT, MAXMEMHEAP);
#endif

  // Setup a NULL block at the end of the heap for fast comparisons with zero.
  theHeap[OSALMEM_LASTBLK_IDX].val = 0;

  // Setup the small-block bucket.
  ff1 = theHeap;
  ff1->val = OSALMEM_SMALLBLK_BUCKET;                   // Set 'len' & clear 'inUse' field.
  // Set 'len' & 'inUse' fields - this is a 'zero data bytes' lifetime allocation to block the
  // small-block bucket from ever being coalesced with the wilderness.
  theHeap[OSALMEM_SMALLBLK_HDRCNT].val = (OSALMEM_HDRSZ | OSALMEM_IN_USE);

  // Setup the wilderness.
  theHeap[OSALMEM_BIGBLK_IDX].val = OSALMEM_BIGBLK_SZ;  // Set 'len' & clear 'inUse' field.

#if ( OSALMEM_METRICS )
  /* Start with the small-block bucket and the wilderness - don't count the
   * end-of-heap NULL block nor the end-of-small-block NULL block.
   */
  blkCnt = blkFree = 2;
#endif
}

void osal_mem_kick(void)
{
  halIntState_t intState;
  osalMemHdr_t *tmp = osal_mem_alloc(1);

  HAL_ASSERT((tmp != NULL));
  HAL_ENTER_CRITICAL_SECTION(intState);  // Hold off interrupts.

  /* All long-lived allocations have filled the LL block reserved in the small-block bucket.
   * Set 'osalMemStat' so searching for memory in this bucket from here onward will only be done
   * for sizes meeting the OSALMEM_SMALL_BLKSZ criteria.
   */
  ff1 = tmp - 1;       // Set 'ff1' to point to the first available memory after the LL block.
  osal_mem_free(tmp);
  osalMemStat = 0x01;  // Set 'osalMemStat' after the free because it enables memory profiling.

  HAL_EXIT_CRITICAL_SECTION(intState);  // Re-enable interrupts.
}

#ifdef DPRINTF_OSALHEAPTRACE
void *osal_mem_alloc_dbg( uint16 size, const char *fname, unsigned lnum )
#else /* DPRINTF_OSALHEAPTRACE */
void *osal_mem_alloc( uint16 size )
#endif /* DPRINTF_OSALHEAPTRACE */
{
  osalMemHdr_t *prev = NULL;
  osalMemHdr_t *hdr;
  halIntState_t intState;
  uint8 coal = 0;

  size += OSALMEM_HDRSZ;

  // Calculate required bytes to add to 'size' to align to halDataAlign_t.
  if ( sizeof( halDataAlign_t ) == 2 )
  {
    size += (size & 0x01);
  }
  else if ( sizeof( halDataAlign_t ) != 1 )
  {
    const uint8 mod = size % sizeof( halDataAlign_t );

    if ( mod != 0 )
    {
      size += (sizeof( halDataAlign_t ) - mod);
    }
  }

  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.

  // Smaller allocations are first attempted in the small-block bucket, and all long-lived
  // allocations are channeled into the LL block reserved within this bucket.
  if ((osalMemStat == 0) || (size <= OSALMEM_SMALL_BLKSZ))
  {
    hdr = ff1;
  }
  else
  {
    hdr = (theHeap + OSALMEM_BIGBLK_IDX);
  }

  do
  {
    if ( hdr->hdr.inUse )
    {
      coal = 0;
    }
    else
    {
      if ( coal != 0 )
      {
#if ( OSALMEM_METRICS )
        blkCnt--;
        blkFree--;
#endif

        prev->hdr.len += hdr->hdr.len;

        if ( prev->hdr.len >= size )
        {
          hdr = prev;
          break;
        }
      }
      else
      {
        if ( hdr->hdr.len >= size )
        {
          break;
        }

        coal = 1;
        prev = hdr;
      }
    }

    hdr = (osalMemHdr_t *)((uint8 *)hdr + hdr->hdr.len);

    if ( hdr->val == 0 )
    {
      hdr = NULL;
      break;
    }
  } while (1);

  if ( hdr != NULL )
  {
    uint16 tmp = hdr->hdr.len - size;

    // Determine whether the threshold for splitting is met.
    if ( tmp >= OSALMEM_MIN_BLKSZ )
    {
      // Split the block before allocating it.
      osalMemHdr_t *next = (osalMemHdr_t *)((uint8 *)hdr + size);
      next->val = tmp;                     // Set 'len' & clear 'inUse' field.
      hdr->val = (size | OSALMEM_IN_USE);  // Set 'len' & 'inUse' field.

#if ( OSALMEM_METRICS )
      blkCnt++;
      if ( blkMax < blkCnt )
      {
        blkMax = blkCnt;
      }
      memAlo += size;
#endif
    }
    else
    {
#if ( OSALMEM_METRICS )
      memAlo += hdr->hdr.len;
      blkFree--;
#endif

      hdr->hdr.inUse = TRUE;
    }

#if ( OSALMEM_METRICS )
    if ( memMax < memAlo )
    {
      memMax = memAlo;
    }
#endif

#if ( OSALMEM_PROFILER )
#if !OSALMEM_PROFILER_LL
    if (osalMemStat != 0)  // Don't profile until after the LL block is filled.
#endif
    {
      uint8 idx;

      for ( idx = 0; idx < OSALMEM_PROMAX; idx++ )
      {
        if ( hdr->hdr.len <= proCnt[idx] )
        {
          break;
        }
      }
      proCur[idx]++;
      if ( proMax[idx] < proCur[idx] )
      {
        proMax[idx] = proCur[idx];
      }
      proTot[idx]++;

      /* A small-block could not be allocated in the small-block bucket.
       * When this occurs significantly frequently, increase the size of the
       * bucket in order to restore better worst case run times. Set the first
       * profiling bucket size in proCnt[] to the small-block bucket size and
       * divide proSmallBlkMiss by the corresponding proTot[] size to get % miss.
       * Best worst case time on TrasmitApp was achieved at a 0-15% miss rate
       * during steady state Tx load, 0% during idle and steady state Rx load.
       */
      if ((hdr->hdr.len <= OSALMEM_SMALL_BLKSZ) && (hdr >= (theHeap + OSALMEM_BIGBLK_IDX)))
      {
        proSmallBlkMiss++;
      }
    }

    (void)osal_memset((uint8 *)(hdr+1), OSALMEM_ALOC, (hdr->hdr.len - OSALMEM_HDRSZ));
#endif

    if ((osalMemStat != 0) && (ff1 == hdr))
    {
      ff1 = (osalMemHdr_t *)((uint8 *)hdr + hdr->hdr.len);
    }

    hdr++;
  }

  HAL_EXIT_CRITICAL_SECTION( intState );  // Re-enable interrupts.
#pragma diag_suppress=Pe767
  HAL_ASSERT(((halDataAlign_t)hdr % sizeof(halDataAlign_t)) == 0);
#pragma diag_default=Pe767

#ifdef DPRINTF_OSALHEAPTRACE
  dprintf("osal_mem_alloc(%u)->%lx:%s:%u\n", size, (unsigned) hdr, fname, lnum);
#endif /* DPRINTF_OSALHEAPTRACE */
  return (void *)hdr;
}

#ifdef DPRINTF_OSALHEAPTRACE
void osal_mem_free_dbg(void *ptr, const char *fname, unsigned lnum)
#else /* DPRINTF_OSALHEAPTRACE */
void osal_mem_free(void *ptr)
#endif /* DPRINTF_OSALHEAPTRACE */
{
  osalMemHdr_t *hdr = (osalMemHdr_t *)ptr - 1;
  halIntState_t intState;

#ifdef DPRINTF_OSALHEAPTRACE
  dprintf("osal_mem_free(%lx):%s:%u\n", (unsigned) ptr, fname, lnum);
#endif /* DPRINTF_OSALHEAPTRACE */

  HAL_ASSERT(((uint8 *)ptr >= (uint8 *)theHeap) && ((uint8 *)ptr < (uint8 *)theHeap+MAXMEMHEAP));
  HAL_ASSERT(hdr->hdr.inUse);

  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.
  hdr->hdr.inUse = FALSE;

  if (ff1 > hdr)
  {
    ff1 = hdr;
  }

#if OSALMEM_PROFILER
#if !OSALMEM_PROFILER_LL
  if (osalMemStat != 0)  // Don't profile until after the LL block is filled.
#endif
  {
    uint8 idx;

    for (idx = 0; idx < OSALMEM_PROMAX; idx++)
    {
      if (hdr->hdr.len <= proCnt[idx])
      {
        break;
      }
    }

    proCur[idx]--;
  }

  (void)osal_memset((uint8 *)(hdr+1), OSALMEM_REIN, (hdr->hdr.len - OSALMEM_HDRSZ) );
#endif
#if OSALMEM_METRICS
  memAlo -= hdr->hdr.len;
  blkFree++;
#endif

  HAL_EXIT_CRITICAL_SECTION( intState );  // Re-enable interrupts.
}

#if OSALMEM_METRICS

uint16 osal_heap_block_max( void )
{
  return blkMax;
}

uint16 osal_heap_block_cnt( void )
{
  return blkCnt;
}

uint16 osal_heap_block_free( void )
{
  return blkFree;
}


uint16 osal_heap_mem_used( void )
{
  return memAlo;
}
#endif

#if defined (ZTOOL_P1) || defined (ZTOOL_P2)

uint16 osal_heap_high_water( void )
{
#if ( OSALMEM_METRICS )
  return memMax;
#else
  return MAXMEMHEAP;
#endif
}
#endif

OSAL_Memory.h

#ifndef OSAL_MEMORY_H
#define OSAL_MEMORY_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "comdef.h"


#if !defined ( OSALMEM_METRICS )
  #define OSALMEM_METRICS  FALSE
#endif

  
#define osal_stack_used()  OnBoard_stack_used()

  void osal_mem_init( void );

  void osal_mem_kick( void );

#ifdef DPRINTF_OSALHEAPTRACE
  void *osal_mem_alloc_dbg( uint16 size, const char *fname, unsigned lnum );
#define osal_mem_alloc(_size ) osal_mem_alloc_dbg(_size, __FILE__, __LINE__)
#else /* DPRINTF_OSALHEAPTRACE */
  void *osal_mem_alloc( uint16 size );
#endif /* DPRINTF_OSALHEAPTRACE */

 /*
  * Free a block of memory.
  */
#ifdef DPRINTF_OSALHEAPTRACE
  void osal_mem_free_dbg( void *ptr, const char *fname, unsigned lnum );
#define osal_mem_free(_ptr ) osal_mem_free_dbg(_ptr, __FILE__, __LINE__)
#else /* DPRINTF_OSALHEAPTRACE */
  void osal_mem_free( void *ptr );
#endif /* DPRINTF_OSALHEAPTRACE */

#if ( OSALMEM_METRICS )
 /*
  * Return the maximum number of blocks ever allocated at once.
  */
  uint16 osal_heap_block_max( void );

 /*
  * Return the current number of blocks now allocated.
  */
  uint16 osal_heap_block_cnt( void );

 /*
  * Return the current number of free blocks.
  */
  uint16 osal_heap_block_free( void );

 /*
  * Return the current number of bytes allocated.
  */
  uint16 osal_heap_mem_used( void );
#endif

#if defined (ZTOOL_P1) || defined (ZTOOL_P2)
 /*
  * Return the highest number of bytes ever used in the heap.
  */
  uint16 osal_heap_high_water( void );
#endif

#ifdef __cplusplus
}
#endif

#endif /* #ifndef OSAL_MEMORY_H */

OSAL_Nv.c

#include "hal_adc.h"
#include "hal_flash.h"
#include "hal_types.h"
#include "OSAL_Nv.h"
#include "ZComDef.h"

#define OSAL_NV_PAGE_SIZE       HAL_FLASH_PAGE_SIZE
#define OSAL_NV_PAGES_USED      HAL_NV_PAGE_CNT
#define OSAL_NV_PAGE_BEG        HAL_NV_PAGE_BEG
#define OSAL_NV_PAGE_END       (OSAL_NV_PAGE_BEG + OSAL_NV_PAGES_USED - 1)

#define OSAL_NV_ACTIVE          0x00
#define OSAL_NV_ERASED          0xFF
#define OSAL_NV_ERASED_ID       0xFFFF
#define OSAL_NV_ZEROED_ID       0x0000
// Reserve MSB of Id to signal a search for the "old" source copy (new write interrupted/failed.)
#define OSAL_NV_SOURCE_ID       0x8000

// In case pages 0-1 are ever used, define a null page value.
#define OSAL_NV_PAGE_NULL       0

// In case item Id 0 is ever used, define a null item value.
#define OSAL_NV_ITEM_NULL       0

#define OSAL_NV_WORD_SIZE       HAL_FLASH_WORD_SIZE

#define OSAL_NV_PAGE_HDR_OFFSET 0

#define OSAL_NV_MAX_HOT         3
static const uint16 hotIds[OSAL_NV_MAX_HOT] = {
  ZCD_NV_NWKKEY,
  ZCD_NV_NWK_ACTIVE_KEY_INFO,
  ZCD_NV_NWK_ALTERN_KEY_INFO,
};

#define OSAL_NV_CHECK_BUS_VOLTAGE  HalAdcCheckVdd(VDD_MIN_NV)

#define OSAL_NV_DATA_SIZE( LEN )                      \
  (((LEN) >= ((uint16)(65536UL - OSAL_NV_WORD_SIZE))) ? \
             ((uint16)(65536UL - OSAL_NV_WORD_SIZE))  : \
             ((((LEN) + OSAL_NV_WORD_SIZE - 1) / OSAL_NV_WORD_SIZE) * OSAL_NV_WORD_SIZE))

#define OSAL_NV_ITEM_SIZE( LEN )                                         \
  (((LEN) >= ((uint16)(65536UL - OSAL_NV_WORD_SIZE - OSAL_NV_HDR_SIZE))) ? \
             ((uint16)(65536UL - OSAL_NV_WORD_SIZE))                     : \
  (((((LEN) + OSAL_NV_WORD_SIZE - 1) / OSAL_NV_WORD_SIZE) * OSAL_NV_WORD_SIZE) + OSAL_NV_HDR_SIZE))

#define COMPACT_PAGE_CLEANUP( COM_PG ) st ( \
  /* In order to recover from a page compaction that is interrupted,\
   * the logic in osal_nv_init() depends upon the following order:\
   * 1. State of the target of compaction is changed to ePgInUse.\
   * 2. Compacted page is erased.\
   */\
  setPageUse( pgRes, TRUE );  /* Mark the reserve page as being in use. */\
  erasePage( (COM_PG) ); \
  \
  pgRes = (COM_PG);           /* Set the reserve page to be the newly erased page. */\
)


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;
// Struct member offsets.
#define OSAL_NV_HDR_ID    0
#define OSAL_NV_HDR_LEN   2
#define OSAL_NV_HDR_CHK   4
#define OSAL_NV_HDR_STAT  6

#define OSAL_NV_HDR_ITEM  2  // Length of any item of a header struct.
#define OSAL_NV_HDR_SIZE  8
#define OSAL_NV_HDR_HALF (OSAL_NV_HDR_SIZE / 2)

typedef struct
{
  uint16 active;
  uint16 inUse;
  uint16 xfer;
  uint16 spare;
} osalNvPgHdr_t;
// Struct member offsets.
#define OSAL_NV_PG_ACTIVE 0
#define OSAL_NV_PG_INUSE  2
#define OSAL_NV_PG_XFER   4
#define OSAL_NV_PG_SPARE  6

#define OSAL_NV_PAGE_HDR_SIZE  8
#define OSAL_NV_PAGE_HDR_HALF (OSAL_NV_PAGE_HDR_SIZE / 2)

typedef enum
{
  eNvXfer,
  eNvZero
} eNvHdrEnum;

typedef enum
{
  ePgActive,
  ePgInUse,
  ePgXfer,
  ePgSpare
} ePgHdrEnum;


#ifndef OAD_KEEP_NV_PAGES
// When NV pages are to remain intact during OAD download,
// the image itself should not include NV pages.
#pragma location="ZIGNV_ADDRESS_SPACE"
__no_init uint8 _nvBuf[OSAL_NV_PAGES_USED * OSAL_NV_PAGE_SIZE];
#pragma required=_nvBuf
#endif // OAD_KEEP_NV_PAGES

// Offset into the page of the first available erased space.
static uint16 pgOff[OSAL_NV_PAGES_USED];

// Count of the bytes lost for the zeroed-out items.
static uint16 pgLost[OSAL_NV_PAGES_USED];

static uint8 pgRes;  // Page reserved for item compacting transfer.

// Saving ~100 code bytes to move a uint8* parameter/return value from findItem() to a global.
static uint8 findPg;

// NV page and offsets for hot items.
static uint8 hotPg[OSAL_NV_MAX_HOT];
static uint16 hotOff[OSAL_NV_MAX_HOT];


static uint8  initNV( void );

static void   setPageUse( uint8 pg, uint8 inUse );
static uint16 initPage( uint8 pg, uint16 id, uint8 findDups );
static void   erasePage( uint8 pg );
static uint8  compactPage( uint8 srcPg, uint16 skipId );

static uint16 findItem( uint16 id );
static uint8  initItem( uint8 flag, uint16 id, uint16 len, void *buf );
static void   setItem( uint8 pg, uint16 offset, eNvHdrEnum stat );
static uint16 setChk( uint8 pg, uint16 offset, uint16 chk );

static uint16 calcChkB( uint16 len, uint8 *buf );
static uint16 calcChkF( uint8 pg, uint16 offset, uint16 len );

static void   writeWord( uint8 pg, uint16 offset, uint8 *buf );
static void   writeWordH( uint8 pg, uint16 offset, uint8 *buf );
static void   writeWordM( uint8 pg, uint16 offset, uint8 *buf, uint16 cnt );
static void   writeBuf( uint8 pg, uint16 offset, uint16 len, uint8 *buf );
static void   xferBuf( uint8 srcPg, uint16 srcOff, uint8 dstPg, uint16 dstOff, uint16 len );

static uint8  writeItem( uint8 pg, uint16 id, uint16 len, void *buf, uint8 flag );
static uint8  hotItem(uint16 id);
static void   hotItemUpdate(uint8 pg, uint16 off, uint16 id);

static uint8 initNV( void )
{
  osalNvPgHdr_t pgHdr;
  uint8 oldPg = OSAL_NV_PAGE_NULL;
  uint8 findDups = FALSE;
  uint8 pg;

  pgRes = OSAL_NV_PAGE_NULL;

  for ( pg = OSAL_NV_PAGE_BEG; pg <= OSAL_NV_PAGE_END; pg++ )
  {
    HalFlashRead(pg, OSAL_NV_PAGE_HDR_OFFSET, (uint8 *)(&pgHdr), OSAL_NV_HDR_SIZE);

    if ( pgHdr.active == OSAL_NV_ERASED_ID )
    {
      if ( pgRes == OSAL_NV_PAGE_NULL )
      {
        pgRes = pg;
      }
      else
      {
        setPageUse( pg, TRUE );
      }
    }
    // An Xfer from this page was in progress.
    else if ( pgHdr.xfer != OSAL_NV_ERASED_ID )
    {
      oldPg = pg;
    }
  }

  // If a page compaction was interrupted before the old page was erased.
  if ( oldPg != OSAL_NV_PAGE_NULL )
  {
    /* Interrupted compaction before the target of compaction was put in use;
     * so erase the target of compaction and start again.
     */
    if ( pgRes != OSAL_NV_PAGE_NULL )
    {
      erasePage( pgRes );
      (void)compactPage( oldPg, OSAL_NV_ITEM_NULL );
    }
    /* Interrupted compaction after the target of compaction was put in use,
     * but before the old page was erased; so erase it now and create a new reserve page.
     */
    else
    {
      erasePage( oldPg );
      pgRes = oldPg;
    }
  }
  else if ( pgRes != OSAL_NV_PAGE_NULL )
  {
    erasePage( pgRes );  // The last page erase could have been interrupted by a power-cycle.
  }
  /* else if there is no reserve page, COMPACT_PAGE_CLEANUP() must have succeeded to put the old
   * reserve page (i.e. the target of the compacted items) into use but got interrupted by a reset
   * while trying to erase the page to be compacted. Such a page should only contain duplicate items
   * (i.e. all items will be marked 'Xfer') and thus should have the lost count equal to the page
   * size less the page header.
   */

  for ( pg = OSAL_NV_PAGE_BEG; pg <= OSAL_NV_PAGE_END; pg++ )
  {
    // Calculate page offset and lost bytes - any "old" item triggers an N^2 re-scan from start.
    if ( initPage( pg, OSAL_NV_ITEM_NULL, findDups ) != OSAL_NV_ITEM_NULL )
    {
      findDups = TRUE;
      pg = (OSAL_NV_PAGE_BEG - 1);  // Pre-decrement so that loop increment will start over at zero.
      continue;
    }
  }

  if (findDups)
  {
    // Final pass to calculate page lost after invalidating duplicate items.
    for ( pg = OSAL_NV_PAGE_BEG; pg <= OSAL_NV_PAGE_END; pg++ )
    {
      (void)initPage( pg, OSAL_NV_ITEM_NULL, FALSE );
    }
  }

  if ( pgRes == OSAL_NV_PAGE_NULL )
  {
    uint8 idx, mostLost = 0;

    for ( idx = 0; idx < OSAL_NV_PAGES_USED; idx++ )
    {
      // Is this the page that was compacted?
      if (pgLost[idx] == (OSAL_NV_PAGE_SIZE - OSAL_NV_PAGE_HDR_SIZE))
      {
        mostLost = idx;
        break;
      }
      /* This check is not expected to be necessary because the above test should always succeed
       * with an early loop exit.
       */
      else if (pgLost[idx] > pgLost[mostLost])
      {
        mostLost = idx;
      }
    }

    pgRes = mostLost + OSAL_NV_PAGE_BEG;
    erasePage( pgRes );  // The last page erase had been interrupted by a power-cycle.
  }

  return TRUE;
}

static void setPageUse( uint8 pg, uint8 inUse )
{
  osalNvPgHdr_t pgHdr;

  pgHdr.active = OSAL_NV_ZEROED_ID;

  if ( inUse )
  {
    pgHdr.inUse = OSAL_NV_ZEROED_ID;
  }
  else
  {
    pgHdr.inUse = OSAL_NV_ERASED_ID;
  }

  writeWord( pg, OSAL_NV_PAGE_HDR_OFFSET, (uint8*)(&pgHdr) );
}

static uint16 initPage( uint8 pg, uint16 id, uint8 findDups )
{
  uint16 offset = OSAL_NV_PAGE_HDR_SIZE;
  uint16 sz, lost = 0;
  osalNvHdr_t hdr;

  do
  {
    HalFlashRead(pg, offset, (uint8 *)(&hdr), OSAL_NV_HDR_SIZE);

    if ( hdr.id == OSAL_NV_ERASED_ID )
    {
      break;
    }

    // Get the actual size in bytes which is the ceiling(hdr.len)
    sz = OSAL_NV_DATA_SIZE( hdr.len );

    // A bad 'len' write has blown away the rest of the page.
    if (sz > (OSAL_NV_PAGE_SIZE - OSAL_NV_HDR_SIZE - offset))
    {
      lost += (OSAL_NV_PAGE_SIZE - offset);
      offset = OSAL_NV_PAGE_SIZE;
      break;
    }

    offset += OSAL_NV_HDR_SIZE;

    if ( hdr.id != OSAL_NV_ZEROED_ID )
    {
      /* This trick allows function to do double duty for findItem() without
       * compromising its essential functionality at powerup initialization.
       */
      if ( id != OSAL_NV_ITEM_NULL )
      {
        /* This trick allows asking to find the old/transferred item in case
         * of a successful new item write that gets interrupted before the
         * old item can be zeroed out.
         */
        if ( (id & 0x7fff) == hdr.id )
        {
          if ( (((id & OSAL_NV_SOURCE_ID) == 0) && (hdr.stat == OSAL_NV_ERASED_ID)) ||
               (((id & OSAL_NV_SOURCE_ID) != 0) && (hdr.stat != OSAL_NV_ERASED_ID)) )
          {
            return offset;
          }
        }
      }
      // When invoked from the osal_nv_init(), verify checksums and find & zero any duplicates.
      else
      {
        if ( hdr.chk == calcChkF( pg, offset, hdr.len ) )
        {
          if ( findDups )
          {
            if ( hdr.stat == OSAL_NV_ERASED_ID )
            {
              /* The trick of setting the MSB of the item Id causes the logic
               * immediately above to return a valid page only if the header 'stat'
               * indicates that it was the older item being transferred.
               */
              uint16 off = findItem( (hdr.id | OSAL_NV_SOURCE_ID) );

              if ( off != OSAL_NV_ITEM_NULL )
              {
                setItem( findPg, off, eNvZero );  // Mark old duplicate as invalid.
              }
            }
          }
          // Any "old" item immediately exits and triggers the N^2 exhaustive initialization.
          else if ( hdr.stat != OSAL_NV_ERASED_ID )
          {
            return OSAL_NV_ERASED_ID;
          }
        }
        else
        {
          setItem( pg, offset, eNvZero );  // Mark bad checksum as invalid.
          lost += (OSAL_NV_HDR_SIZE + sz);
        }
      }
    }
    else
    {
      lost += (OSAL_NV_HDR_SIZE + sz);
    }
    offset += sz;

  } while (offset < (OSAL_NV_PAGE_SIZE - OSAL_NV_HDR_SIZE));

  pgOff[pg - OSAL_NV_PAGE_BEG] = offset;
  pgLost[pg - OSAL_NV_PAGE_BEG] = lost;

  return OSAL_NV_ITEM_NULL;
}

static void erasePage( uint8 pg )
{
  HalFlashErase(pg);

  pgOff[pg - OSAL_NV_PAGE_BEG] = OSAL_NV_PAGE_HDR_SIZE;
  pgLost[pg - OSAL_NV_PAGE_BEG] = 0;
}


static uint8 compactPage( uint8 srcPg, uint16 skipId )
{
  uint16 srcOff;
  uint8 rtrn;

  // To minimize code size, only check for a clean page here where it's absolutely required.
  for (srcOff = 0; srcOff < OSAL_NV_PAGE_SIZE; srcOff++)
  {
    HalFlashRead(pgRes, srcOff, &rtrn, 1);
    if (rtrn != OSAL_NV_ERASED)
    {
      erasePage(pgRes);
      return FALSE;
    }
  }

  srcOff = OSAL_NV_PAGE_HDR_SIZE;
  rtrn = TRUE;

  while ( srcOff < (OSAL_NV_PAGE_SIZE - OSAL_NV_HDR_SIZE ) )
  {
    osalNvHdr_t hdr;
    uint16 sz, dstOff = pgOff[pgRes-OSAL_NV_PAGE_BEG];

    HalFlashRead(srcPg, srcOff, (uint8 *)(&hdr), OSAL_NV_HDR_SIZE);

    if ( hdr.id == OSAL_NV_ERASED_ID )
    {
      break;
    }

    // Get the actual size in bytes which is the ceiling(hdr.len)
    sz = OSAL_NV_DATA_SIZE( hdr.len );

    if ( sz > (OSAL_NV_PAGE_SIZE - OSAL_NV_HDR_SIZE - srcOff) )
    {
      break;
    }

    if ( sz > (OSAL_NV_PAGE_SIZE - OSAL_NV_HDR_SIZE - dstOff) )
    {
      rtrn = FALSE;
      break;
    }

    srcOff += OSAL_NV_HDR_SIZE;

    if ( (hdr.id != OSAL_NV_ZEROED_ID) && (hdr.id != skipId) )
    {
      if ( hdr.chk == calcChkF( srcPg, srcOff, hdr.len ) )
      {
        /* Prevent excessive re-writes to item header caused by numerous, rapid, & successive
         * OSAL_Nv interruptions caused by resets.
         */
        if ( hdr.stat == OSAL_NV_ERASED_ID )
        {
          setItem( srcPg, srcOff, eNvXfer );
        }

        if ( writeItem( pgRes, hdr.id, hdr.len, NULL, FALSE ) )
        {
          dstOff += OSAL_NV_HDR_SIZE;
          xferBuf( srcPg, srcOff, pgRes, dstOff, sz );
          // Calculate and write the new checksum.
          if (hdr.chk == calcChkF(pgRes, dstOff, hdr.len))
          {
            if ( hdr.chk != setChk( pgRes, dstOff, hdr.chk ) )
            {
              rtrn = FALSE;
              break;
            }
            else
            {
              hotItemUpdate(pgRes, dstOff, hdr.id);
            }
          }
          else
          {
            rtrn = FALSE;
            break;
          }
        }
        else
        {
          rtrn = FALSE;
          break;
        }
      }
    }

    srcOff += sz;
  }

  if (rtrn == FALSE)
  {
    erasePage(pgRes);
  }
  else if (skipId == OSAL_NV_ITEM_NULL)
  {
    COMPACT_PAGE_CLEANUP(srcPg);
  }
  // else invoking function must cleanup.

  return rtrn;
}

static uint16 findItem( uint16 id )
{
  uint16 off;
  uint8 pg;

  for ( pg = OSAL_NV_PAGE_BEG; pg <= OSAL_NV_PAGE_END; pg++ )
  {
    if ( (off = initPage( pg, id, FALSE )) != OSAL_NV_ITEM_NULL )
    {
      findPg = pg;
      return off;
    }
  }

  // Now attempt to find the item as the "old" item of a failed/interrupted NV write.
  if ( (id & OSAL_NV_SOURCE_ID) == 0 )
  {
    return findItem( id | OSAL_NV_SOURCE_ID );
  }
  else
  {
    findPg = OSAL_NV_PAGE_NULL;
    return OSAL_NV_ITEM_NULL;
  }
}

static uint8 initItem( uint8 flag, uint16 id, uint16 len, void *buf )
{
  uint16 sz = OSAL_NV_ITEM_SIZE( len );
  uint8 rtrn = OSAL_NV_PAGE_NULL;
  uint8 cnt = OSAL_NV_PAGES_USED;
  uint8 pg = pgRes+1;  // Set to 1 after the reserve page to even wear across all available pages.

  do {
    if (pg >= OSAL_NV_PAGE_BEG+OSAL_NV_PAGES_USED)
    {
      pg = OSAL_NV_PAGE_BEG;
    }
    if ( pg != pgRes )
    {
      uint8 idx = pg - OSAL_NV_PAGE_BEG;
      if ( sz <= (OSAL_NV_PAGE_SIZE - pgOff[idx] + pgLost[idx]) )
      {
        break;
      }
    }
    pg++;
  } while (--cnt);

  if (cnt)
  {
    // Item fits if an old page is compacted.
    if ( sz > (OSAL_NV_PAGE_SIZE - pgOff[pg - OSAL_NV_PAGE_BEG]) )
    {
      osalNvPgHdr_t pgHdr;

      /* Prevent excessive re-writes to page header caused by numerous, rapid, & successive
       * OSAL_Nv interruptions caused by resets.
       */
      HalFlashRead(pg, OSAL_NV_PAGE_HDR_OFFSET, (uint8 *)(&pgHdr), OSAL_NV_PAGE_HDR_SIZE);
      if ( pgHdr.xfer == OSAL_NV_ERASED_ID )
      {
        // Mark the old page as being in process of compaction.
        sz = OSAL_NV_ZEROED_ID;
        writeWordH( pg, OSAL_NV_PG_XFER, (uint8*)(&sz) );
      }

      /* First the old page is compacted, then the new item will be the last one written to what
       * had been the reserved page.
       */
      if (compactPage( pg, id ))
      {
        if ( writeItem( pgRes, id, len, buf, flag ) )
        {
          rtrn = pgRes;
        }

        if ( flag == FALSE )
        {
          /* Overload 'buf' as an OUT parameter to pass back to the calling function
           * the old page to be cleaned up.
           */
          *(uint8 *)buf = pg;
        }
        else
        {
          /* Safe to do the compacted page cleanup even if writeItem() above failed because the
           * item does not yet exist since this call with flag==TRUE is from osal_nv_item_init().
           */
          COMPACT_PAGE_CLEANUP( pg );
        }
      }
    }
    else
    {
      if ( writeItem( pg, id, len, buf, flag ) )
      {
        rtrn = pg;
      }
    }
  }

  return rtrn;
}

static void setItem( uint8 pg, uint16 offset, eNvHdrEnum stat )
{
  osalNvHdr_t hdr;

  offset -= OSAL_NV_HDR_SIZE;
  HalFlashRead(pg, offset, (uint8 *)(&hdr), OSAL_NV_HDR_SIZE);

  if ( stat == eNvXfer )
  {
    hdr.stat = OSAL_NV_ACTIVE;
    writeWord( pg, offset+OSAL_NV_HDR_CHK, (uint8*)(&(hdr.chk)) );
  }
  else // if ( stat == eNvZero )
  {
    uint16 sz = ((hdr.len + (OSAL_NV_WORD_SIZE-1)) / OSAL_NV_WORD_SIZE) * OSAL_NV_WORD_SIZE +
                                                                          OSAL_NV_HDR_SIZE;
    hdr.id = 0;
    writeWord( pg, offset, (uint8 *)(&hdr) );
    pgLost[pg-OSAL_NV_PAGE_BEG] += sz;
  }
}

static uint16 setChk( uint8 pg, uint16 offset, uint16 chk )
{
  offset -= OSAL_NV_WORD_SIZE;
  writeWordH( pg, offset, (uint8 *)&chk );
  HalFlashRead( pg, offset, (uint8 *)(&chk), sizeof( chk ) );

  return chk;
}

static uint16 calcChkB( uint16 len, uint8 *buf )
{
  uint8 fill = len % OSAL_NV_WORD_SIZE;
  uint16 chk;

  if ( !buf )
  {
    chk = len * OSAL_NV_ERASED;
  }
  else
  {
    chk = 0;
    while ( len-- )
    {
      chk += *buf++;
    }
  }

  // calcChkF() will calculate over OSAL_NV_WORD_SIZE alignment.
  if ( fill )
  {
    chk += (OSAL_NV_WORD_SIZE - fill) * OSAL_NV_ERASED;
  }

  return chk;
}

static uint16 calcChkF( uint8 pg, uint16 offset, uint16 len )
{
  uint16 chk = 0;

  len = (len + (OSAL_NV_WORD_SIZE-1)) / OSAL_NV_WORD_SIZE;

  while ( len-- )
  {
    uint8 cnt, tmp[OSAL_NV_WORD_SIZE];

    HalFlashRead(pg, offset, tmp, OSAL_NV_WORD_SIZE);
    offset += OSAL_NV_WORD_SIZE;

    for ( cnt = 0; cnt < OSAL_NV_WORD_SIZE; cnt++ )
    {
      chk += tmp[cnt];
    }
  }

  return chk;
}


static void writeWord( uint8 pg, uint16 offset, uint8 *buf )
{
  offset = (offset / HAL_FLASH_WORD_SIZE) +
          ((uint16)pg * (HAL_FLASH_PAGE_SIZE / HAL_FLASH_WORD_SIZE));

  HalFlashWrite(offset, buf, 1);
}

static void writeWordM( uint8 pg, uint16 offset, uint8 *buf, uint16 cnt )
{
  offset = (offset / HAL_FLASH_WORD_SIZE) +
          ((uint16)pg * (HAL_FLASH_PAGE_SIZE / HAL_FLASH_WORD_SIZE));
  HalFlashWrite(offset, buf, cnt);
}


static void writeWordH( uint8 pg, uint16 offset, uint8 *buf )
{
  uint8 tmp[4];

  tmp[0] = buf[0];
  tmp[1] = buf[1];
  tmp[2] = OSAL_NV_ERASED;
  tmp[3] = OSAL_NV_ERASED;

  writeWord( pg, offset, tmp );
}

static void writeBuf( uint8 dstPg, uint16 dstOff, uint16 len, uint8 *buf )
{
  uint8 rem = dstOff % OSAL_NV_WORD_SIZE;
  uint8 tmp[OSAL_NV_WORD_SIZE];

  if ( rem )
  {
    dstOff = (dstOff / OSAL_NV_WORD_SIZE) * OSAL_NV_WORD_SIZE;
    HalFlashRead(dstPg, dstOff, tmp, OSAL_NV_WORD_SIZE);

    while ( (rem < OSAL_NV_WORD_SIZE) && len )
    {
      tmp[rem++] = *buf++;
      len--;
    }

    writeWord( dstPg, dstOff, tmp );
    dstOff += OSAL_NV_WORD_SIZE;
  }

  rem = len % OSAL_NV_WORD_SIZE;
  len /= OSAL_NV_WORD_SIZE;

  if ( len )
  {
    writeWordM( dstPg, dstOff, buf, len );
    dstOff += OSAL_NV_WORD_SIZE * len;
    buf += OSAL_NV_WORD_SIZE * len;
  }

  if ( rem )
  {
    uint8 idx = 0;
    HalFlashRead(dstPg, dstOff, tmp, OSAL_NV_WORD_SIZE);
    while ( rem-- )
    {
      tmp[idx++] = *buf++;
    }
    writeWord( dstPg, dstOff, tmp );
  }
}

static void xferBuf( uint8 srcPg, uint16 srcOff, uint8 dstPg, uint16 dstOff, uint16 len )
{
  uint8 rem = dstOff % OSAL_NV_WORD_SIZE;
  uint8 tmp[OSAL_NV_WORD_SIZE];

  if ( rem )
  {
    dstOff -= rem;
    HalFlashRead(dstPg, dstOff, tmp, OSAL_NV_WORD_SIZE);

    while ( (rem < OSAL_NV_WORD_SIZE) && len )
    {
      HalFlashRead(srcPg, srcOff, tmp+rem, 1);
      srcOff++;
      rem++;
      len--;
    }

    writeWord( dstPg, dstOff, tmp );
    dstOff += OSAL_NV_WORD_SIZE;
  }

  rem = len % OSAL_NV_WORD_SIZE;
  len /= OSAL_NV_WORD_SIZE;

  while ( len-- )
  {
    HalFlashRead(srcPg, srcOff, tmp, OSAL_NV_WORD_SIZE);
    srcOff += OSAL_NV_WORD_SIZE;
    writeWord( dstPg, dstOff, tmp );
    dstOff += OSAL_NV_WORD_SIZE;
  }

  if ( rem )
  {
    uint8 idx = 0;
    HalFlashRead(dstPg, dstOff, tmp, OSAL_NV_WORD_SIZE);
    while ( rem-- )
    {
      HalFlashRead(srcPg, srcOff, tmp+idx, 1);
      srcOff++;
      idx++;
    }
    writeWord( dstPg, dstOff, tmp );
  }
}


static uint8 writeItem( uint8 pg, uint16 id, uint16 len, void *buf, uint8 flag )
{
  uint16 offset = pgOff[pg-OSAL_NV_PAGE_BEG];
  uint8 rtrn = FALSE;
  osalNvHdr_t hdr;

  hdr.id = id;
  hdr.len = len;

  writeWord( pg, offset, (uint8 *)&hdr );
  HalFlashRead(pg, offset, (uint8 *)(&hdr), OSAL_NV_HDR_SIZE);

  if ( (hdr.id == id) && (hdr.len == len) )
  {
    if ( flag )
    {
      hdr.chk = calcChkB( len, buf );

      offset += OSAL_NV_HDR_SIZE;
      if ( buf != NULL )
      {
        writeBuf( pg, offset, len, buf );
      }

      if ( hdr.chk == calcChkF( pg, offset, len ) )
      {
        if ( hdr.chk == setChk( pg, offset, hdr.chk ) )
        {
          hotItemUpdate(pg, offset, hdr.id);
          rtrn = TRUE;
        }
      }
    }
    else
    {
      rtrn = TRUE;
    }

    len = OSAL_NV_ITEM_SIZE( hdr.len );
  }
  else
  {
    len = OSAL_NV_ITEM_SIZE( hdr.len );

    if (len > (OSAL_NV_PAGE_SIZE - pgOff[pg - OSAL_NV_PAGE_BEG]))
    {
      len = (OSAL_NV_PAGE_SIZE - pgOff[pg - OSAL_NV_PAGE_BEG]);
    }

    pgLost[pg - OSAL_NV_PAGE_BEG] += len;
  }
  pgOff[pg - OSAL_NV_PAGE_BEG] += len;

  return rtrn;
}

static uint8 hotItem(uint16 id)
{
  uint8 hotIdx;

  for (hotIdx = 0; hotIdx < OSAL_NV_MAX_HOT; hotIdx++)
  {
    if (hotIds[hotIdx] == id)
    {
      break;
    }
  }

  return hotIdx;
}


static void hotItemUpdate(uint8 pg, uint16 off, uint16 id)
{
  uint8 hotIdx = hotItem(id);

  if (hotIdx < OSAL_NV_MAX_HOT)
  {
    {
      hotPg[hotIdx] = pg;
      hotOff[hotIdx] = off;
    }
  }
}


void osal_nv_init( void *p )
{
  (void)p;  // Suppress Lint warning.
  (void)initNV();  // Always returns TRUE after pages have been erased.
}

uint8 osal_nv_item_init( uint16 id, uint16 len, void *buf )
{
  uint16 offset;

  if ( !OSAL_NV_CHECK_BUS_VOLTAGE )
  {
    return NV_OPER_FAILED;
  }
  else if ((offset = findItem(id)) != OSAL_NV_ITEM_NULL)
  {
    // Re-populate the NV hot item data if the corresponding items are already established.
    hotItemUpdate(findPg, offset, id);

    return SUCCESS;
  }
  else if ( initItem( TRUE, id, len, buf ) != OSAL_NV_PAGE_NULL )
  {
    return NV_ITEM_UNINIT;
  }
  else
  {
    return NV_OPER_FAILED;
  }
}

uint16 osal_nv_item_len( uint16 id )
{
  osalNvHdr_t hdr;
  uint16 offset;
  uint8 hotIdx;

  if ((hotIdx = hotItem(id)) < OSAL_NV_MAX_HOT)
  {
    findPg = hotPg[hotIdx];
    offset = hotOff[hotIdx];
  }
  else if ((offset = findItem(id)) == OSAL_NV_ITEM_NULL)
  {
    return 0;
  }

  HalFlashRead(findPg, (offset - OSAL_NV_HDR_SIZE), (uint8 *)(&hdr), OSAL_NV_HDR_SIZE);
  return hdr.len;
}

uint8 osal_nv_write( uint16 id, uint16 ndx, uint16 len, void *buf )
{
  uint8 rtrn = SUCCESS;

  if ( !OSAL_NV_CHECK_BUS_VOLTAGE )
  {
    return NV_OPER_FAILED;
  }
  else if ( len != 0 )
  {
    osalNvHdr_t hdr;
    uint16 origOff, srcOff;
    uint16 cnt, chk;
    uint8 *ptr, srcPg;

    origOff = srcOff = findItem( id );
    srcPg = findPg;
    if ( srcOff == OSAL_NV_ITEM_NULL )
    {
      return NV_ITEM_UNINIT;
    }

    HalFlashRead(srcPg, (srcOff - OSAL_NV_HDR_SIZE), (uint8 *)(&hdr), OSAL_NV_HDR_SIZE);
    if ( hdr.len < (ndx + len) )
    {
      return NV_OPER_FAILED;
    }

    srcOff += ndx;
    ptr = buf;
    cnt = len;
    chk = 0;
    while ( cnt-- )
    {
      uint8 tmp;
      HalFlashRead(srcPg, srcOff, &tmp, 1);
      if ( tmp != *ptr )
      {
        chk = 1;  // Mark that at least one byte is different.
        // Calculate expected checksum after transferring old data and writing new data.
        hdr.chk -= tmp;
        hdr.chk += *ptr;
      }
      srcOff++;
      ptr++;
    }

    if ( chk != 0 )  // If the buffer to write is different in one or more bytes.
    {
      uint8 comPg = OSAL_NV_PAGE_NULL;
      uint8 dstPg = initItem( FALSE, id, hdr.len, &comPg );

      if ( dstPg != OSAL_NV_PAGE_NULL )
      {
        uint16 tmp = OSAL_NV_DATA_SIZE( hdr.len );
        uint16 dstOff = pgOff[dstPg-OSAL_NV_PAGE_BEG] - tmp;
        srcOff = origOff;

        /* Prevent excessive re-writes to item header caused by numerous, rapid, & successive
         * OSAL_Nv interruptions caused by resets.
         */
        if ( hdr.stat == OSAL_NV_ERASED_ID )
        {
          setItem( srcPg, srcOff, eNvXfer );
        }

        xferBuf( srcPg, srcOff, dstPg, dstOff, ndx );
        srcOff += ndx;
        dstOff += ndx;

        writeBuf( dstPg, dstOff, len, buf );
        srcOff += len;
        dstOff += len;

        xferBuf( srcPg, srcOff, dstPg, dstOff, (hdr.len-ndx-len) );

        // Calculate and write the new checksum.
        dstOff = pgOff[dstPg-OSAL_NV_PAGE_BEG] - tmp;

        if ( hdr.chk == calcChkF( dstPg, dstOff, hdr.len ) )
        {
          if ( hdr.chk != setChk( dstPg, dstOff, hdr.chk ) )
          {
            rtrn = NV_OPER_FAILED;
          }
          else
          {
            hotItemUpdate(dstPg, dstOff, hdr.id);
          }
        }
        else
        {
          rtrn = NV_OPER_FAILED;
        }
      }
      else
      {
        rtrn = NV_OPER_FAILED;
      }

      if ( comPg != OSAL_NV_PAGE_NULL )
      {
        /* Even though the page compaction succeeded, if the new item is coming from the compacted
         * page and writing the new value failed, then the compaction must be aborted.
         */
        if ( (srcPg == comPg) && (rtrn == NV_OPER_FAILED) )
        {
          erasePage( pgRes );
        }
        else
        {
          COMPACT_PAGE_CLEANUP( comPg );
        }
      }

      /* Zero of the old item must wait until after compact page cleanup has finished - if the item
       * is zeroed before and cleanup is interrupted by a power-cycle, the new item can be lost.
       */
      if ( (srcPg != comPg) && (rtrn != NV_OPER_FAILED) )
      {
        setItem( srcPg, origOff, eNvZero );
      }
    }
  }

  return rtrn;
}

uint8 osal_nv_read( uint16 id, uint16 ndx, uint16 len, void *buf )
{
  uint16 offset;
  uint8 hotIdx;

  if ((hotIdx = hotItem(id)) < OSAL_NV_MAX_HOT)
  {
    HalFlashRead(hotPg[hotIdx], hotOff[hotIdx]+ndx, buf, len);
    return SUCCESS;
  }

  if ((offset = findItem(id)) == OSAL_NV_ITEM_NULL)
  {
    return NV_OPER_FAILED;
  }
  else
  {
    HalFlashRead(findPg, offset+ndx, buf, len);
    return SUCCESS;
  }
}

uint8 osal_nv_delete( uint16 id, uint16 len )
{
  uint16 length;
  uint16 offset;

  offset = findItem( id );
  if ( offset == OSAL_NV_ITEM_NULL )
  {
    // NV item does not exist
    return NV_ITEM_UNINIT;
  }

  length = osal_nv_item_len( id );
  if ( length != len )
  {
    // NV item has different length
    return NV_BAD_ITEM_LEN;
  }

  // Set item header ID to zero to 'delete' the item
  setItem( findPg, offset, eNvZero );

  // Verify that item has been removed
  offset = findItem( id );
  if ( offset != OSAL_NV_ITEM_NULL )
  {
    // Still there
    return NV_OPER_FAILED;
  }
  else
  {
    // Yes, it's gone
    return SUCCESS;
  }
}

OSAL_Nv.h

#ifndef OSAL_NV_H
#define OSAL_NV_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "hal_types.h"

extern void osal_nv_init( void *p );

extern uint8 osal_nv_item_init( uint16 id, uint16 len, void *buf );

extern uint8 osal_nv_read( uint16 id, uint16 offset, uint16 len, void *buf );

extern uint8 osal_nv_write( uint16 id, uint16 offset, uint16 len, void *buf );

extern uint16 osal_nv_item_len( uint16 id );

extern uint8 osal_nv_delete( uint16 id, uint16 len );


#ifdef __cplusplus
}
#endif

#endif /* OSAL_NV.H */

OSAL_PwrMgr.c

#include "comdef.h"
#include "OnBoard.h"
#include "OSAL.h"
#include "OSAL_Tasks.h"
#include "OSAL_Timers.h"
#include "OSAL_PwrMgr.h"

pwrmgr_attribute_t pwrmgr_attribute;

void osal_pwrmgr_init( void )
{
  pwrmgr_attribute.pwrmgr_device = PWRMGR_ALWAYS_ON; // Default to no power conservation.
  pwrmgr_attribute.pwrmgr_task_state = 0;            // Cleared.  All set to conserve
}

void osal_pwrmgr_device( uint8 pwrmgr_device )
{
  pwrmgr_attribute.pwrmgr_device = pwrmgr_device;
}

uint8 osal_pwrmgr_task_state( uint8 task_id, uint8 state )
{
  if ( task_id >= tasksCnt )
    return ( INVALID_TASK );

  if ( state == PWRMGR_CONSERVE )
  {
    // Clear the task state flag
    pwrmgr_attribute.pwrmgr_task_state &= ~(1 << task_id );
  }
  else
  {
    // Set the task state flag
    pwrmgr_attribute.pwrmgr_task_state |= (1 << task_id);
  }

  return ( SUCCESS );
}

#if defined( POWER_SAVING )

void osal_pwrmgr_powerconserve( void )
{
  uint16        next;
  halIntState_t intState;

  // Should we even look into power conservation
  if ( pwrmgr_attribute.pwrmgr_device != PWRMGR_ALWAYS_ON )
  {
    // Are all tasks in agreement to conserve
    if ( pwrmgr_attribute.pwrmgr_task_state == 0 )
    {
      // Hold off interrupts.
      HAL_ENTER_CRITICAL_SECTION( intState );

      // Get next time-out
      next = osal_next_timeout();

      // Re-enable interrupts.
      HAL_EXIT_CRITICAL_SECTION( intState );

      // Put the processor into sleep mode
      OSAL_SET_CPU_INTO_SLEEP( next );
    }
  }
}
#endif /* POWER_SAVING */

OSAL_PwrMgr.h

#ifndef OSAL_PWRMGR_H
#define OSAL_PWRMGR_H

#ifdef __cplusplus
extern "C"
{
#endif

typedef struct
{
  uint16 pwrmgr_task_state;
  uint16 pwrmgr_next_timeout;
  uint16 accumulated_sleep_time;
  uint8  pwrmgr_device;
} pwrmgr_attribute_t;

/* With PWRMGR_ALWAYS_ON selection, there is no power savings and the
 * device is most likely on mains power. The PWRMGR_BATTERY selection allows
 * the HAL sleep manager to enter SLEEP LITE state or SLEEP DEEP state.
 */
#define PWRMGR_ALWAYS_ON  0
#define PWRMGR_BATTERY    1

#define PWRMGR_CONSERVE 0
#define PWRMGR_HOLD     1

extern pwrmgr_attribute_t pwrmgr_attribute;

  extern void osal_pwrmgr_init( void );

  extern uint8 osal_pwrmgr_task_state( uint8 task_id, uint8 state );

  extern void osal_pwrmgr_device( uint8 pwrmgr_device );


  extern void osal_pwrmgr_powerconserve( void );


#ifdef __cplusplus
}
#endif

#endif /* OSAL_PWRMGR_H */

OSAL_Tasks.h

#ifndef OSAL_TASKS_H
#define OSAL_TASKS_H

#ifdef __cplusplus
extern "C"
{
#endif

#define TASK_NO_TASK      0xFF

typedef unsigned short (*pTaskEventHandlerFn)( unsigned char task_id, unsigned short event );

extern const pTaskEventHandlerFn tasksArr[];
extern const uint8 tasksCnt;
extern uint16 *tasksEvents;

extern void osalInitTasks( void );


#ifdef __cplusplus
}
#endif

#endif /* OSAL_TASKS_H */

OSAL_Timers.c

#include "comdef.h"
#include "OnBoard.h"
#include "OSAL.h"
#include "OSAL_Timers.h"
#include "hal_timer.h"

typedef struct
{
  void   *next;
  uint16 timeout;
  uint16 event_flag;
  uint8  task_id;
  uint16 reloadTimeout;
} osalTimerRec_t;

osalTimerRec_t *timerHead;

// Milliseconds since last reboot
static uint32 osal_systemClock;

osalTimerRec_t  *osalAddTimer( uint8 task_id, uint16 event_flag, uint16 timeout );
osalTimerRec_t *osalFindTimer( uint8 task_id, uint16 event_flag );
void osalDeleteTimer( osalTimerRec_t *rmTimer );

void osalTimerInit( void )
{
  osal_systemClock = 0;
}

osalTimerRec_t * osalAddTimer( uint8 task_id, uint16 event_flag, uint16 timeout )
{
  osalTimerRec_t *newTimer;
  osalTimerRec_t *srchTimer;

  // Look for an existing timer first
  newTimer = osalFindTimer( task_id, event_flag );
  if ( newTimer )
  {
    // Timer is found - update it.
    newTimer->timeout = timeout;

    return ( newTimer );
  }
  else
  {
    // New Timer
    newTimer = osal_mem_alloc( sizeof( osalTimerRec_t ) );

    if ( newTimer )
    {
      // Fill in new timer
      newTimer->task_id = task_id;
      newTimer->event_flag = event_flag;
      newTimer->timeout = timeout;
      newTimer->next = (void *)NULL;
      newTimer->reloadTimeout = 0;

      // Does the timer list already exist
      if ( timerHead == NULL )
      {
        // Start task list
        timerHead = newTimer;
      }
      else
      {
        // Add it to the end of the timer list
        srchTimer = timerHead;

        // Stop at the last record
        while ( srchTimer->next )
          srchTimer = srchTimer->next;

        // Add to the list
        srchTimer->next = newTimer;
      }

      return ( newTimer );
    }
    else
      return ( (osalTimerRec_t *)NULL );
  }
}

osalTimerRec_t *osalFindTimer( uint8 task_id, uint16 event_flag )
{
  osalTimerRec_t *srchTimer;

  // Head of the timer list
  srchTimer = timerHead;

  // Stop when found or at the end
  while ( srchTimer )
  {
    if ( srchTimer->event_flag == event_flag &&
         srchTimer->task_id == task_id )
      break;

    // Not this one, check another
    srchTimer = srchTimer->next;
  }

  return ( srchTimer );
}

void osalDeleteTimer( osalTimerRec_t *rmTimer )
{
  // Does the timer list really exist
  if ( rmTimer )
  {
    // Clear the event flag and osalTimerUpdate() will delete 
    // the timer from the list.
    rmTimer->event_flag = 0;
  }
}

uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value )
{
  halIntState_t intState;
  osalTimerRec_t *newTimer;

  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.

  // Add timer
  newTimer = osalAddTimer( taskID, event_id, timeout_value );

  HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.

  return ( (newTimer != NULL) ? SUCCESS : NO_TIMER_AVAIL );
}

uint8 osal_start_reload_timer( uint8 taskID, uint16 event_id, uint16 timeout_value )
{
  halIntState_t intState;
  osalTimerRec_t *newTimer;

  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.

  // Add timer
  newTimer = osalAddTimer( taskID, event_id, timeout_value );
  if ( newTimer )
  {
    // Load the reload timeout value
    newTimer->reloadTimeout = timeout_value;
  }

  HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.

  return ( (newTimer != NULL) ? SUCCESS : NO_TIMER_AVAIL );
}

uint8 osal_stop_timerEx( uint8 task_id, uint16 event_id )
{
  halIntState_t intState;
  osalTimerRec_t *foundTimer;

  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.

  // Find the timer to stop
  foundTimer = osalFindTimer( task_id, event_id );
  if ( foundTimer )
  {
    osalDeleteTimer( foundTimer );
  }

  HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.

  return ( (foundTimer != NULL) ? SUCCESS : INVALID_EVENT_ID );
}

uint16 osal_get_timeoutEx( uint8 task_id, uint16 event_id )
{
  halIntState_t intState;
  uint16 rtrn = 0;
  osalTimerRec_t *tmr;

  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.

  tmr = osalFindTimer( task_id, event_id );

  if ( tmr )
  {
    rtrn = tmr->timeout;
  }

  HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.

  return rtrn;
}

uint8 osal_timer_num_active( void )
{
  halIntState_t intState;
  uint8 num_timers = 0;
  osalTimerRec_t *srchTimer;

  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.

  // Head of the timer list
  srchTimer = timerHead;

  // Count timers in the list
  while ( srchTimer != NULL )
  {
    num_timers++;
    srchTimer = srchTimer->next;
  }

  HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.

  return num_timers;
}

void osalTimerUpdate( uint16 updateTime )
{
  halIntState_t intState;
  osalTimerRec_t *srchTimer;
  osalTimerRec_t *prevTimer;

  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.
  // Update the system time
  osal_systemClock += updateTime;
  HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.

  // Look for open timer slot
  if ( timerHead != NULL )
  {
    // Add it to the end of the timer list
    srchTimer = timerHead;
    prevTimer = (void *)NULL;

    // Look for open timer slot
    while ( srchTimer )
    {
      osalTimerRec_t *freeTimer = NULL;
     
      HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.
      
      if (srchTimer->timeout <= updateTime)
      {
        srchTimer->timeout = 0;
      }
      else
      {
        srchTimer->timeout = srchTimer->timeout - updateTime;
      }
      
      // Check for reloading
      if ( (srchTimer->timeout == 0) && (srchTimer->reloadTimeout) && (srchTimer->event_flag) )
      {
        // Notify the task of a timeout
        osal_set_event( srchTimer->task_id, srchTimer->event_flag );
        
        // Reload the timer timeout value
        srchTimer->timeout = srchTimer->reloadTimeout;
      }
      
      // When timeout or delete (event_flag == 0)
      if ( srchTimer->timeout == 0 || srchTimer->event_flag == 0 )
      {
        // Take out of list
        if ( prevTimer == NULL )
          timerHead = srchTimer->next;
        else
          prevTimer->next = srchTimer->next;

        // Setup to free memory
        freeTimer = srchTimer;

        // Next
        srchTimer = srchTimer->next;
      }
      else
      {
        // Get next
        prevTimer = srchTimer;
        srchTimer = srchTimer->next;
      }
      
      HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.
      
      if ( freeTimer )
      {
        if ( freeTimer->timeout == 0 )
        {
          osal_set_event( freeTimer->task_id, freeTimer->event_flag );
        }
        osal_mem_free( freeTimer );
      }
    }
  }
}

#ifdef POWER_SAVING

void osal_adjust_timers( void )
{
  uint16 eTime;

  if ( timerHead != NULL )
  {
    // Compute elapsed time (msec)
    eTime = TimerElapsed() /  TICK_COUNT;

    if ( eTime )
      osalTimerUpdate( eTime );
  }
}

uint16 osal_next_timeout( void )
{
  uint16 nextTimeout;
  osalTimerRec_t *srchTimer;

  if ( timerHead != NULL )
  {
    // Head of the timer list
    srchTimer = timerHead;
    nextTimeout = OSAL_TIMERS_MAX_TIMEOUT;

    // Look for the next timeout timer
    while ( srchTimer != NULL )
    {
      if (srchTimer->timeout < nextTimeout)
      {
        nextTimeout = srchTimer->timeout;
      }
      // Check next timer
      srchTimer = srchTimer->next;
    }
  }
  else
  {
    // No timers
    nextTimeout = 0;
  }

  return ( nextTimeout );
}
#endif // POWER_SAVING

uint32 osal_GetSystemClock( void )
{
  return ( osal_systemClock );
}

OSAL_Timers.h

#ifndef OSAL_TIMERS_H
#define OSAL_TIMERS_H

#ifdef __cplusplus
extern "C"
{
#endif

#define OSAL_TIMERS_MAX_TIMEOUT 0xFFFF

  extern void osalTimerInit( void );

  extern uint8 osal_start_timerEx( uint8 task_id, uint16 event_id, uint16 timeout_value );
 
  extern uint8 osal_start_reload_timer( uint8 taskID, uint16 event_id, uint16 timeout_value );

  extern uint8 osal_stop_timerEx( uint8 task_id, uint16 event_id );

  extern uint16 osal_get_timeoutEx( uint8 task_id, uint16 event_id );

  extern void osal_timer_ISR( void );

  extern void osal_adjust_timers( void );

  extern void osalTimerUpdate( uint16 updateTime );

  extern uint8 osal_timer_num_active( void );


  extern void osal_sleep_timers( void );
  extern void osal_unsleep_timers( void );

  extern uint32 osal_GetSystemClock( void );

  extern uint16 osal_next_timeout( void );

#ifdef __cplusplus
}
#endif

#endif /* OSAL_TIMERS_H */

ZComDef.h

#ifndef ZCOMDEF_H
#define ZCOMDEF_H

#ifdef __cplusplus
extern "C"
{
#endif


#include "comdef.h"
#include "saddr.h"

#define osal_cpyExtAddr(a, b)   sAddrExtCpy((a), (const uint8 *)(b))
#define osal_ExtAddrEqual(a, b) sAddrExtCmp((const uint8 *)(a), (const uint8 *)(b))
#define osal_copyAddress(a, b)  sAddrCpy( (sAddr_t *)(a), (const sAddr_t *)(b) )

// Build Device Types - Used during compilation
//   These are the types of devices to build
//   Bit masked into ZSTACK_DEVICE_BUILD
#define DEVICE_BUILD_COORDINATOR    0x01
#define DEVICE_BUILD_ROUTER         0x02
#define DEVICE_BUILD_ENDDEVICE      0x04

/*** Return Values ***/
#define ZSUCCESS                  SUCCESS

/*** Component IDs ***/
#define COMPID_OSAL               0
#define COMPID_MTEL               1
#define COMPID_MTSPCI             2
#define COMPID_NWK                3
#define COMPID_NWKIF              4
#define COMPID_MACCB              5
#define COMPID_MAC                6
#define COMPID_APP                7
#define COMPID_TEST               8

#define COMPID_RTG                9
#define COMPID_DATA               11

/* Temp CompIDs for testing */
#define COMPID_TEST_NWK_STARTUP           20
#define COMPID_TEST_SCAN_CONFIRM          21
#define COMPID_TEST_ASSOC_CONFIRM         22
#define COMPID_TEST_REMOTE_DATA_CONFIRM   23

// OSAL NV item IDs
#define ZCD_NV_EXTADDR                    0x0001
#define ZCD_NV_BOOTCOUNTER                0x0002
#define ZCD_NV_STARTUP_OPTION             0x0003
#define ZCD_NV_START_DELAY                0x0004

// NWK Layer NV item IDs
#define ZCD_NV_NIB                        0x0021
#define ZCD_NV_DEVICE_LIST                0x0022
#define ZCD_NV_ADDRMGR                    0x0023
#define ZCD_NV_POLL_RATE                  0x0024
#define ZCD_NV_QUEUED_POLL_RATE           0x0025
#define ZCD_NV_RESPONSE_POLL_RATE         0x0026
#define ZCD_NV_REJOIN_POLL_RATE           0x0027
#define ZCD_NV_DATA_RETRIES               0x0028
#define ZCD_NV_POLL_FAILURE_RETRIES       0x0029
#define ZCD_NV_STACK_PROFILE              0x002A
#define ZCD_NV_INDIRECT_MSG_TIMEOUT       0x002B
#define ZCD_NV_ROUTE_EXPIRY_TIME          0x002C
#define ZCD_NV_EXTENDED_PAN_ID            0x002D
#define ZCD_NV_BCAST_RETRIES              0x002E
#define ZCD_NV_PASSIVE_ACK_TIMEOUT        0x002F
#define ZCD_NV_BCAST_DELIVERY_TIME        0x0030
#define ZCD_NV_NWK_MODE                   0x0031
#define ZCD_NV_CONCENTRATOR_ENABLE        0x0032
#define ZCD_NV_CONCENTRATOR_DISCOVERY     0x0033
#define ZCD_NV_CONCENTRATOR_RADIUS        0x0034
#define ZCD_NV_CONCENTRATOR_RC            0x0036
#define ZCD_NV_NWK_MGR_MODE               0x0037
#define ZCD_NV_SRC_RTG_EXPIRY_TIME        0x0038
#define ZCD_NV_ROUTE_DISCOVERY_TIME       0x0039
#define ZCD_NV_NWK_ACTIVE_KEY_INFO        0x003A
#define ZCD_NV_NWK_ALTERN_KEY_INFO        0x003B
#define ZCD_NV_ROUTER_OFF_ASSOC_CLEANUP   0x003C


// APS Layer NV item IDs
#define ZCD_NV_BINDING_TABLE              0x0041
#define ZCD_NV_GROUP_TABLE                0x0042
#define ZCD_NV_APS_FRAME_RETRIES          0x0043
#define ZCD_NV_APS_ACK_WAIT_DURATION      0x0044
#define ZCD_NV_APS_ACK_WAIT_MULTIPLIER    0x0045
#define ZCD_NV_BINDING_TIME               0x0046
#define ZCD_NV_APS_USE_EXT_PANID          0x0047
#define ZCD_NV_APS_USE_INSECURE_JOIN      0x0048

#define ZCD_NV_APS_NONMEMBER_RADIUS       0x004B     // Multicast non_member radius
#define ZCD_NV_APS_LINK_KEY_TABLE         0x004C

// Security NV Item IDs
#define ZCD_NV_SECURITY_LEVEL             0x0061
#define ZCD_NV_PRECFGKEY                  0x0062
#define ZCD_NV_PRECFGKEYS_ENABLE          0x0063
#define ZCD_NV_SECURITY_MODE              0x0064
#define ZCD_NV_SECURE_PERMIT_JOIN         0x0065

#define ZCD_NV_IMPLICIT_CERTIFICATE       0x0069
#define ZCD_NV_DEVICE_PRIVATE_KEY         0x006A
#define ZCD_NV_CA_PUBLIC_KEY              0x006B

#define ZCD_NV_USE_DEFAULT_TCLK           0x006D
#define ZCD_NV_TRUSTCENTER_ADDR           0x006E
#define ZCD_NV_RNG_COUNTER                0x006F
#define ZCD_NV_RANDOM_SEED                0x0070

// ZDO NV Item IDs
#define ZCD_NV_USERDESC                   0x0081
#define ZCD_NV_NWKKEY                     0x0082
#define ZCD_NV_PANID                      0x0083
#define ZCD_NV_CHANLIST                   0x0084
#define ZCD_NV_LEAVE_CTRL                 0x0085
#define ZCD_NV_SCAN_DURATION              0x0086
#define ZCD_NV_LOGICAL_TYPE               0x0087
#define ZCD_NV_NWKMGR_MIN_TX              0x0088
#define ZCD_NV_NWKMGR_ADDR                0x0089

#define ZCD_NV_ZDO_DIRECT_CB              0x008F

// ZCL NV item IDs
#define ZCD_NV_SCENE_TABLE                0x0091

// Non-standard NV item IDs
#define ZCD_NV_SAPI_ENDPOINT              0x00A1

// NV Items Reserved for Commissioning Cluster Startup Attribute Set (SAS):
// 0x00B1 - 0x00BF: Parameters related to APS and NWK layers
// 0x00C1 - 0x00CF: Parameters related to Security
// 0x00D1 - 0x00DF: Current key parameters
#define ZCD_NV_SAS_SHORT_ADDR             0x00B1
#define ZCD_NV_SAS_EXT_PANID              0x00B2
#define ZCD_NV_SAS_PANID                  0x00B3
#define ZCD_NV_SAS_CHANNEL_MASK           0x00B4
#define ZCD_NV_SAS_PROTOCOL_VER           0x00B5
#define ZCD_NV_SAS_STACK_PROFILE          0x00B6
#define ZCD_NV_SAS_STARTUP_CTRL           0x00B7

#define ZCD_NV_SAS_TC_ADDR                0x00C1
#define ZCD_NV_SAS_TC_MASTER_KEY          0x00C2
#define ZCD_NV_SAS_NWK_KEY                0x00C3
#define ZCD_NV_SAS_USE_INSEC_JOIN         0x00C4
#define ZCD_NV_SAS_PRECFG_LINK_KEY        0x00C5
#define ZCD_NV_SAS_NWK_KEY_SEQ_NUM        0x00C6
#define ZCD_NV_SAS_NWK_KEY_TYPE           0x00C7
#define ZCD_NV_SAS_NWK_MGR_ADDR           0x00C8

#define ZCD_NV_SAS_CURR_TC_MASTER_KEY     0x00D1
#define ZCD_NV_SAS_CURR_NWK_KEY           0x00D2
#define ZCD_NV_SAS_CURR_PRECFG_LINK_KEY   0x00D3

// NV Items Reserved for Trust Center Link Key Table entries
// 0x0101 - 0x01FF
#define ZCD_NV_TCLK_TABLE_START           0x0101
#define ZCD_NV_TCLK_TABLE_END             0x01FF

// NV Items Reserved for APS Link Key Table entries
// 0x0201 - 0x02FF
#define ZCD_NV_APS_LINK_KEY_DATA_START    0x0201     // APS key data
#define ZCD_NV_APS_LINK_KEY_DATA_END      0x02FF

// NV Items Reserved for Master Key Table entries
// 0x0301 - 0x03FF
#define ZCD_NV_MASTER_KEY_DATA_START      0x0301     // Master key data
#define ZCD_NV_MASTER_KEY_DATA_END        0x03FF

// NV Items Reserved for applications (user applications)
// 0x0401 ?0x0FFF


// ZCD_NV_STARTUP_OPTION values
//   These are bit weighted - you can OR these together.
//   Setting one of these bits will set their associated NV items
//   to code initialized values.
#define ZCD_STARTOPT_DEFAULT_CONFIG_STATE  0x01
#define ZCD_STARTOPT_DEFAULT_NETWORK_STATE 0x02
#define ZCD_STARTOPT_AUTO_START            0x04
#define ZCD_STARTOPT_CLEAR_CONFIG   ZCD_STARTOPT_DEFAULT_CONFIG_STATE
#define ZCD_STARTOPT_CLEAR_STATE    ZCD_STARTOPT_DEFAULT_NETWORK_STATE


#define ZCL_KE_IMPLICIT_CERTIFICATE_LEN                  48
#define ZCL_KE_CA_PUBLIC_KEY_LEN                         22
#define ZCL_KE_DEVICE_PRIVATE_KEY_LEN                    21

/*** Data Types ***/
typedef uint8   byte;
typedef uint16  UINT16;
typedef int16   INT16;

enum
{
  AddrNotPresent = 0,
  AddrGroup = 1,
  Addr16Bit = 2,
  Addr64Bit = 3,
  AddrBroadcast = 15
};

#define Z_EXTADDR_LEN   8

typedef byte ZLongAddr_t[Z_EXTADDR_LEN];

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

// Redefined Generic Status Return Values for code backwards compatibility
#define ZSuccess                    SUCCESS
#define ZFailure                    FAILURE
#define ZInvalidParameter           INVALIDPARAMETER

// ZStack status values must start at 0x10, after the generic status values (defined in comdef.h)
#define ZMemError                   0x10
#define ZBufferFull                 0x11
#define ZUnsupportedMode            0x12
#define ZMacMemError                0x13

#define ZSapiInProgress             0x20
#define ZSapiTimeout                0x21
#define ZSapiInit                   0x22

#define ZNotAuthorized              0x7E

#define ZMalformedCmd               0x80
#define ZUnsupClusterCmd            0x81

// OTA Status values
#define ZOtaAbort                   0x95
#define ZOtaImageInvalid            0x96
#define ZOtaWaitForData             0x97
#define ZOtaNoImageAvailable        0x98
#define ZOtaRequireMoreImage        0x99

// APS status values
#define ZApsFail                    0xb1
#define ZApsTableFull               0xb2
#define ZApsIllegalRequest          0xb3
#define ZApsInvalidBinding          0xb4
#define ZApsUnsupportedAttrib       0xb5
#define ZApsNotSupported            0xb6
#define ZApsNoAck                   0xb7
#define ZApsDuplicateEntry          0xb8
#define ZApsNoBoundDevice           0xb9
#define ZApsNotAllowed              0xba
#define ZApsNotAuthenticated        0xbb
	
	// Security status values
#define ZSecNoKey                   0xa1
#define ZSecOldFrmCount             0xa2
#define ZSecMaxFrmCount             0xa3
#define ZSecCcmFail                 0xa4

	// NWK status values
#define ZNwkInvalidParam            0xc1
#define ZNwkInvalidRequest          0xc2
#define ZNwkNotPermitted            0xc3
#define ZNwkStartupFailure          0xc4
#define ZNwkAlreadyPresent          0xc5
#define ZNwkSyncFailure             0xc6
#define ZNwkTableFull               0xc7
#define ZNwkUnknownDevice           0xc8
#define ZNwkUnsupportedAttribute    0xc9
#define ZNwkNoNetworks              0xca
#define ZNwkLeaveUnconfirmed        0xcb
#define ZNwkNoAck                   0xcc  // not in spec
#define ZNwkNoRoute                 0xcd

	// MAC status values
#define ZMacSuccess                 0x00
#define ZMacBeaconLoss              0xe0
#define ZMacChannelAccessFailure    0xe1
#define ZMacDenied                  0xe2
#define ZMacDisableTrxFailure       0xe3
#define ZMacFailedSecurityCheck     0xe4
#define ZMacFrameTooLong            0xe5
#define ZMacInvalidGTS              0xe6
#define ZMacInvalidHandle           0xe7
#define ZMacInvalidParameter        0xe8
#define ZMacNoACK                   0xe9
#define ZMacNoBeacon                0xea
#define ZMacNoData                  0xeb
#define ZMacNoShortAddr             0xec
#define ZMacOutOfCap                0xed
#define ZMacPANIDConflict           0xee
#define ZMacRealignment             0xef
#define ZMacTransactionExpired      0xf0
#define ZMacTransactionOverFlow     0xf1
#define ZMacTxActive                0xf2
#define ZMacUnAvailableKey          0xf3
#define ZMacUnsupportedAttribute    0xf4
#define ZMacUnsupported             0xf5
#define ZMacSrcMatchInvalidIndex    0xff

typedef Status_t ZStatus_t;

typedef struct
{
  uint8  txCounter;    // Counter of transmission success/failures
  uint8  txCost;       // Average of sending rssi values if link staus is enabled
                       // i.e. NWK_LINK_STATUS_PERIOD is defined as non zero
  uint8  rxLqi;        // average of received rssi values
                       // needs to be converted to link cost (1-7) before used
  uint8  inKeySeqNum;  // security key sequence number
  uint32 inFrmCntr;    // security frame counter..
  uint16 txFailure;    // higher values indicate more failures
} linkInfo_t;

#define SPI_INCOMING_ZTOOL_PORT   0x21    // Raw data from ZTool Port (not implemented)
#define SPI_INCOMING_ZAPP_DATA    0x22    // Raw data from the ZAPP port (see serialApp.c)
#define MT_SYS_APP_MSG            0x23    // Raw data from an MT Sys message
#define MT_SYS_APP_RSP_MSG        0x24    // Raw data output for an MT Sys message
#define MT_SYS_OTA_MSG            0x25    // Raw data output for an MT OTA Rsp

#define AF_DATA_CONFIRM_CMD       0xFD    // Data confirmation
#define AF_INCOMING_MSG_CMD       0x1A    // Incoming MSG type message
#define AF_INCOMING_KVP_CMD       0x1B    // Incoming KVP type message
#define AF_INCOMING_GRP_KVP_CMD   0x1C    // Incoming Group KVP type message

//#define KEY_CHANGE                0xC0    // Key Events

#define ZDO_NEW_DSTADDR           0xD0    // ZDO has received a new DstAddr for this app
#define ZDO_STATE_CHANGE          0xD1    // ZDO has changed the device's network state
#define ZDO_MATCH_DESC_RSP_SENT   0xD2    // ZDO match descriptor response was sent
#define ZDO_CB_MSG                0xD3    // ZDO incoming message callback
#define ZDO_NETWORK_REPORT        0xD4    // ZDO received a Network Report message
#define ZDO_NETWORK_UPDATE        0xD5    // ZDO received a Network Update message
#define ZDO_ADDR_CHANGE_IND       0xD6    // ZDO was informed of device address change

#define NM_CHANNEL_INTERFERE      0x31    // NwkMgr received a Channel Interference message
#define NM_ED_SCAN_CONFIRM        0x32    // NwkMgr received an ED Scan Confirm message
#define SAPS_CHANNEL_CHANGE       0x33    // Stub APS has changed the device's channel
#define ZCL_INCOMING_MSG          0x34    // Incoming ZCL foundation message
#define ZCL_KEY_ESTABLISH_IND     0x35    // ZCL Key Establishment Completion Indication
#define ZCL_OTA_CALLBACK_IND      0x36    // ZCL OTA Completion Indication


#ifdef __cplusplus
}
#endif

#endif /* ZCOMDEF_H */

Profile(应用框架层)

AF.c

#include "OSAL.h"
#include "AF.h"
#include "nwk_globals.h"
#include "nwk_util.h"
#include "aps_groups.h"
#include "ZDProfile.h"
#include "aps_frag.h"
#include "rtg.h"

#if defined ( MT_AF_CB_FUNC )
  #include "MT_AF.h"
#endif

#if defined ( INTER_PAN )
  #include "stub_aps.h"
#endif

#define afSend( dstAddr, srcEP, cID, len, buf, transID, options, radius ) \
        AF_DataRequest( (dstAddr), afFindEndPointDesc( (srcEP) ), \
                          (cID), (len), (buf), (transID), (options), (radius) )


epList_t *epList;

static void afBuildMSGIncoming( aps_FrameFormat_t *aff, endPointDesc_t *epDesc,
                zAddrType_t *SrcAddress, uint16 SrcPanId, NLDE_Signal_t *sig,
                uint8 nwkSeqNum, uint8 SecurityUse, uint32 timestamp );

static epList_t *afFindEndPointDescList( uint8 EndPoint );

static pDescCB afGetDescCB( endPointDesc_t *epDesc );

epList_t *afRegisterExtended( endPointDesc_t *epDesc, pDescCB descFn )
{
  epList_t *ep = osal_mem_alloc(sizeof(epList_t));

  if (ep != NULL)
  {
    ep->nextDesc = epList;
    epList = ep;
    ep->epDesc = epDesc;
    ep->pfnDescCB = descFn;
    ep->apsfCfg.frameDelay = APSF_DEFAULT_INTERFRAME_DELAY;
    ep->apsfCfg.windowSize = APSF_DEFAULT_WINDOW_SIZE;
    ep->flags = eEP_AllowMatch;  // Default to allow Match Descriptor.
  }

  return ep;
}

afStatus_t afRegister( endPointDesc_t *epDesc )
{
  if (afFindEndPointDescList(epDesc->endPoint))  // Look for duplicate endpoint.
  {
    return afStatus_INVALID_PARAMETER;
  }

  return ((NULL == afRegisterExtended(epDesc, NULL)) ? afStatus_MEM_FAIL : afStatus_SUCCESS);
}

afStatus_t afDelete( uint8 EndPoint )
{
  epList_t *epCurrent;
  epList_t *epPrevious;

  if (epList != NULL)
  {
    epPrevious = epCurrent = epList;

    // first element of the list matches
    if (epCurrent->epDesc->endPoint == EndPoint)
    {
      epList = epCurrent->nextDesc;
      osal_mem_free(epCurrent);

      return (afStatus_SUCCESS);
    }
    else
    {
      // search the list
      for (epCurrent = epPrevious->nextDesc; epCurrent != NULL; epPrevious = epCurrent)
      {
        if (epCurrent->epDesc->endPoint == EndPoint)
        {
          epPrevious->nextDesc = epCurrent->nextDesc;
          osal_mem_free(epCurrent);

          // delete the entry and free the memory
          return (afStatus_SUCCESS);
        }
      }
    }

    // no endpoint found
    return (afStatus_INVALID_PARAMETER);
  }
  else
  {
    // epList is empty
    return (afStatus_FAILED);
  }
}
void afDataConfirm( uint8 endPoint, uint8 transID, ZStatus_t status )
{
  endPointDesc_t *epDesc;
  afDataConfirm_t *msgPtr;

  // Find the endpoint description
  epDesc = afFindEndPointDesc( endPoint );
  if ( epDesc == NULL )
    return;

  // Determine the incoming command type
  msgPtr = (afDataConfirm_t *)osal_msg_allocate( sizeof(afDataConfirm_t) );
  if ( msgPtr )
  {
    // Build the Data Confirm message
    msgPtr->hdr.event = AF_DATA_CONFIRM_CMD;
    msgPtr->hdr.status = status;
    msgPtr->endpoint = endPoint;
    msgPtr->transID = transID;

#if defined ( MT_AF_CB_FUNC )
    /* If MT has subscribed for this callback, don't send as a message. */
    if ( AFCB_CHECK(CB_ID_AF_DATA_CNF,*(epDesc->task_id)) )
    {
      /* Send callback if it's subscribed */
      MT_AfDataConfirm ((void *)msgPtr);
      /* Release the memory. */
      osal_msg_deallocate( (void *)msgPtr );
    }
    else
#endif
    {
      /* send message through task message */
      osal_msg_send( *(epDesc->task_id), (uint8 *)msgPtr );
    }
  }
}

void afIncomingData( aps_FrameFormat_t *aff, zAddrType_t *SrcAddress, uint16 SrcPanId,
                     NLDE_Signal_t *sig, uint8 nwkSeqNum, uint8 SecurityUse, uint32 timestamp )
{
  endPointDesc_t *epDesc = NULL;
  epList_t *pList = epList;
#if !defined ( APS_NO_GROUPS )
  uint8 grpEp = APS_GROUPS_EP_NOT_FOUND;
#endif

  if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) )
  {
#if !defined ( APS_NO_GROUPS )
    // Find the first endpoint for this group
    grpEp = aps_FindGroupForEndpoint( aff->GroupID, APS_GROUPS_FIND_FIRST );
    if ( grpEp == APS_GROUPS_EP_NOT_FOUND )
      return;   // No endpoint found

    epDesc = afFindEndPointDesc( grpEp );
    if ( epDesc == NULL )
      return;   // Endpoint descriptor not found

    pList = afFindEndPointDescList( epDesc->endPoint );
#else
    return; // Not supported
#endif
  }
  else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT )
  {
    // Set the list
    if ( pList != NULL )
    {
      epDesc = pList->epDesc;
    }
  }
  else if ( (epDesc = afFindEndPointDesc( aff->DstEndPoint )) )
  {
    pList = afFindEndPointDescList( epDesc->endPoint );
  }

  while ( epDesc )
  {
    uint16 epProfileID = 0xFFFF;  // Invalid Profile ID

    if ( pList->pfnDescCB )
    {
      uint16 *pID = (uint16 *)(pList->pfnDescCB(
                                 AF_DESCRIPTOR_PROFILE_ID, epDesc->endPoint ));
      if ( pID )
      {
        epProfileID = *pID;
        osal_mem_free( pID );
      }
    }
    else if ( epDesc->simpleDesc )
    {
      epProfileID = epDesc->simpleDesc->AppProfId;
    }

    if ( (aff->ProfileID == epProfileID) ||
         ((epDesc->endPoint == ZDO_EP) && (aff->ProfileID == ZDO_PROFILE_ID)) )
    {
      {
        // Save original endpoint
        uint8 endpoint = aff->DstEndPoint;

        // overwrite with descriptor's endpoint
        aff->DstEndPoint = epDesc->endPoint;

        afBuildMSGIncoming( aff, epDesc, SrcAddress, SrcPanId, sig,
                           nwkSeqNum, SecurityUse, timestamp );

        // Restore with original endpoint
        aff->DstEndPoint = endpoint;
      }
    }

    if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) )
    {
#if !defined ( APS_NO_GROUPS )
      // Find the next endpoint for this group
      grpEp = aps_FindGroupForEndpoint( aff->GroupID, grpEp );
      if ( grpEp == APS_GROUPS_EP_NOT_FOUND )
        return;   // No endpoint found

      epDesc = afFindEndPointDesc( grpEp );
      if ( epDesc == NULL )
        return;   // Endpoint descriptor not found

      pList = afFindEndPointDescList( epDesc->endPoint );
#else
      return;
#endif
    }
    else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT )
    {
      pList = pList->nextDesc;
      if ( pList )
        epDesc = pList->epDesc;
      else
        epDesc = NULL;
    }
    else
      epDesc = NULL;
  }
}

static void afBuildMSGIncoming( aps_FrameFormat_t *aff, endPointDesc_t *epDesc,
                 zAddrType_t *SrcAddress, uint16 SrcPanId, NLDE_Signal_t *sig,
                 uint8 nwkSeqNum, uint8 SecurityUse, uint32 timestamp )
{
  afIncomingMSGPacket_t *MSGpkt;
  const uint8 len = sizeof( afIncomingMSGPacket_t ) + aff->asduLength;
  uint8 *asdu = aff->asdu;
  MSGpkt = (afIncomingMSGPacket_t *)osal_msg_allocate( len );

  if ( MSGpkt == NULL )
  {
    return;
  }

  MSGpkt->hdr.event = AF_INCOMING_MSG_CMD;
  MSGpkt->groupId = aff->GroupID;
  MSGpkt->clusterId = aff->ClusterID;
  afCopyAddress( &MSGpkt->srcAddr, SrcAddress );
  MSGpkt->srcAddr.endPoint = aff->SrcEndPoint;
  MSGpkt->endPoint = epDesc->endPoint;
  MSGpkt->wasBroadcast = aff->wasBroadcast;
  MSGpkt->LinkQuality = sig->LinkQuality;
  MSGpkt->correlation = sig->correlation;
  MSGpkt->rssi = sig->rssi;
  MSGpkt->SecurityUse = SecurityUse;
  MSGpkt->timestamp = timestamp;
  MSGpkt->nwkSeqNum = nwkSeqNum;
  MSGpkt->macDestAddr = aff->macDestAddr;
  MSGpkt->srcAddr.panId = SrcPanId;
  MSGpkt->cmd.TransSeqNumber = 0;
  MSGpkt->cmd.DataLength = aff->asduLength;

  if ( MSGpkt->cmd.DataLength )
  {
    MSGpkt->cmd.Data = (uint8 *)(MSGpkt + 1);
    osal_memcpy( MSGpkt->cmd.Data, asdu, MSGpkt->cmd.DataLength );
  }
  else
  {
    MSGpkt->cmd.Data = NULL;
  }

#if defined ( MT_AF_CB_FUNC )
  // If ZDO or SAPI have registered for this endpoint, dont intercept it here
  if (AFCB_CHECK(CB_ID_AF_DATA_IND, *(epDesc->task_id)))
  {
    MT_AfIncomingMsg( (void *)MSGpkt );
    // Release the memory.
    osal_msg_deallocate( (void *)MSGpkt );
  }
  else
#endif
  {
    // Send message through task message.
    osal_msg_send( *(epDesc->task_id), (uint8 *)MSGpkt );
  }
}

uint8 AF_DataRequestDiscoverRoute = TRUE;
afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP,
                           uint16 cID, uint16 len, uint8 *buf, uint8 *transID,
                           uint8 options, uint8 radius )
{
  pDescCB pfnDescCB;
  ZStatus_t stat;
  APSDE_DataReq_t req;
  afDataReqMTU_t mtu;

  // Verify source end point
  if ( srcEP == NULL )
  {
    return afStatus_INVALID_PARAMETER;
  }

#if !defined( REFLECTOR )
  if ( dstAddr->addrMode == afAddrNotPresent )
  {
    return afStatus_INVALID_PARAMETER;
  }
#endif

  // Check if route is available before sending data
  if ( options & AF_LIMIT_CONCENTRATOR  )
  {
    if ( dstAddr->addrMode != afAddr16Bit )
    {
      return ( afStatus_INVALID_PARAMETER );
    }

    // First, make sure the destination is not its self, then check for an existing route.
    if ( (dstAddr->addr.shortAddr != NLME_GetShortAddr())
        && (RTG_CheckRtStatus( dstAddr->addr.shortAddr, RT_ACTIVE, (MTO_ROUTE | NO_ROUTE_CACHE) ) != RTG_SUCCESS) )
    {
      // A valid route to a concentrator wasn't found
      return ( afStatus_NO_ROUTE );
    }
  }

  // Validate broadcasting
  if ( ( dstAddr->addrMode == afAddr16Bit     ) ||
       ( dstAddr->addrMode == afAddrBroadcast )    )
  {
    // Check for valid broadcast values
    if( ADDR_NOT_BCAST != NLME_IsAddressBroadcast( dstAddr->addr.shortAddr )  )
    {
      // Force mode to broadcast
      dstAddr->addrMode = afAddrBroadcast;
    }
    else
    {
      // Address is not a valid broadcast type
      if ( dstAddr->addrMode == afAddrBroadcast )
      {
        return afStatus_INVALID_PARAMETER;
      }
    }
  }
  else if ( dstAddr->addrMode != afAddr64Bit &&
            dstAddr->addrMode != afAddrGroup &&
            dstAddr->addrMode != afAddrNotPresent )
  {
    return afStatus_INVALID_PARAMETER;
  }

  // Set destination address
  req.dstAddr.addrMode = dstAddr->addrMode;
  if ( dstAddr->addrMode == afAddr64Bit )
    osal_cpyExtAddr( req.dstAddr.addr.extAddr, dstAddr->addr.extAddr );
  else
    req.dstAddr.addr.shortAddr = dstAddr->addr.shortAddr;

  req.profileID = ZDO_PROFILE_ID;

  if ( (pfnDescCB = afGetDescCB( srcEP )) )
  {
    uint16 *pID = (uint16 *)(pfnDescCB(
                                 AF_DESCRIPTOR_PROFILE_ID, srcEP->endPoint ));
    if ( pID )
    {
      req.profileID = *pID;
      osal_mem_free( pID );
    }
  }
  else if ( srcEP->simpleDesc )
  {
    req.profileID = srcEP->simpleDesc->AppProfId;
  }

  req.txOptions = 0;

  if ( ( options & AF_ACK_REQUEST              ) &&
       ( req.dstAddr.addrMode != AddrBroadcast ) &&
       ( req.dstAddr.addrMode != AddrGroup     )    )
  {
    req.txOptions |=  APS_TX_OPTIONS_ACK;
  }

  if ( options & AF_SKIP_ROUTING )
  {
    req.txOptions |=  APS_TX_OPTIONS_SKIP_ROUTING;
  }

  if ( options & AF_EN_SECURITY )
  {
    req.txOptions |= APS_TX_OPTIONS_SECURITY_ENABLE;
    mtu.aps.secure = TRUE;
  }
  else
  {
    mtu.aps.secure = FALSE;
  }

  if ( options & AF_PREPROCESS )
  {
    req.txOptions |=  APS_TX_OPTIONS_PREPROCESS;
  }

  mtu.kvp = FALSE;

  req.transID       = *transID;
  req.srcEP         = srcEP->endPoint;
  req.dstEP         = dstAddr->endPoint;
  req.clusterID     = cID;
  req.asduLen       = len;
  req.asdu          = buf;
  req.discoverRoute = AF_DataRequestDiscoverRoute;//(uint8)((options & AF_DISCV_ROUTE) ? 1 : 0);
  req.radiusCounter = radius;
#if defined ( INTER_PAN )
  req.dstPanId      = dstAddr->panId;

  if ( StubAPS_InterPan( dstAddr->panId, dstAddr->endPoint ) )
  {
    if ( len > INTERP_DataReqMTU() )
    {
      stat = afStatus_INVALID_PARAMETER;
    }
    else
    {
      stat = INTERP_DataReq( &req );
    }
  }
  else
#endif // INTER_PAN
  {
    if (len > afDataReqMTU( &mtu ) )
    {
      if (apsfSendFragmented)
      {
        stat = (*apsfSendFragmented)( &req );
      }
      else
      {
        stat = afStatus_INVALID_PARAMETER;
      }
    }
    else
    {
      stat = APSDE_DataReq( &req );
    }
  }

  if ( (req.dstAddr.addrMode == Addr16Bit) &&
       (req.dstAddr.addr.shortAddr == NLME_GetShortAddr()) )
  {
    afDataConfirm( srcEP->endPoint, *transID, stat );
  }

  if ( stat == afStatus_SUCCESS )
  {
    (*transID)++;
  }

  return (afStatus_t)stat;
}

#if defined ( ZIGBEE_SOURCE_ROUTING )


afStatus_t AF_DataRequestSrcRtg( afAddrType_t *dstAddr, endPointDesc_t *srcEP,
                           uint16 cID, uint16 len, uint8 *buf, uint8 *transID,
                           uint8 options, uint8 radius, uint8 relayCnt, uint16* pRelayList )
{
  uint8 status;

  /* Add the source route to the source routing table */
  status = RTG_AddSrcRtgEntry_Guaranteed( dstAddr->addr.shortAddr, relayCnt,
                                         pRelayList );

  if( status == RTG_SUCCESS)
  {
    /* Call AF_DataRequest to send the data */
    status = AF_DataRequest( dstAddr, srcEP, cID, len, buf, transID, options, radius );
  }
  else if( status == RTG_INVALID_PATH )
  {
    /* The source route relay count is exceeding the network limit */
    status = afStatus_INVALID_PARAMETER;
  }
  else
  {
    /* The guaranteed adding entry fails due to memory failure */
    status = afStatus_MEM_FAIL;
  }
  return status;
}

#endif

static epList_t *afFindEndPointDescList( uint8 EndPoint )
{
  epList_t *epSearch;

  for (epSearch = epList; epSearch != NULL; epSearch = epSearch->nextDesc)
  {
    if (epSearch->epDesc->endPoint == EndPoint)
    {
      break;
    }
  }

  return epSearch;
}

endPointDesc_t *afFindEndPointDesc( uint8 EndPoint )
{
  epList_t *epSearch;

  // Look for the endpoint
  epSearch = afFindEndPointDescList( EndPoint );

  if ( epSearch )
    return ( epSearch->epDesc );
  else
    return ( (endPointDesc_t *)NULL );
}

uint8 afFindSimpleDesc( SimpleDescriptionFormat_t **ppDesc, uint8 EP )
{
  epList_t *epItem = afFindEndPointDescList( EP );
  uint8 rtrn = FALSE;

  if ( epItem )
  {
    if ( epItem->pfnDescCB )
    {
      *ppDesc = epItem->pfnDescCB( AF_DESCRIPTOR_SIMPLE, EP );
      rtrn = TRUE;
    }
    else
    {
      *ppDesc = epItem->epDesc->simpleDesc;
    }
  }
  else
  {
    *ppDesc = NULL;
  }

  return rtrn;
}

static pDescCB afGetDescCB( endPointDesc_t *epDesc )
{
  epList_t *epSearch;

  // Start at the beginning
  epSearch = epList;

  // Look through the list until the end
  while ( epSearch )
  {
    // Is there a match?
    if ( epSearch->epDesc == epDesc )
    {
      return ( epSearch->pfnDescCB );
    }
    else
      epSearch = epSearch->nextDesc;  // Next entry
  }

  return ( (pDescCB)NULL );
}

uint8 afDataReqMTU( afDataReqMTU_t* fields )
{
  uint8 len;
  uint8 hdr;

  if ( fields->kvp == TRUE )
  {
    hdr = AF_HDR_KVP_MAX_LEN;
  }
  else
  {
    hdr = AF_HDR_V1_1_MAX_LEN;
  }

  len = (uint8)(APSDE_DataReqMTU(&fields->aps) - hdr);

  return len;
}

uint8 afGetMatch( uint8 ep )
{
  epList_t *epSearch;

  // Look for the endpoint
  epSearch = afFindEndPointDescList( ep );

  if ( epSearch )
  {
    if ( epSearch->flags & eEP_AllowMatch )
      return ( TRUE );
    else
      return ( FALSE );
  }
  else
    return ( FALSE );
}

uint8 afSetMatch( uint8 ep, uint8 action )
{
  epList_t *epSearch;

  // Look for the endpoint
  epSearch = afFindEndPointDescList( ep );

  if ( epSearch )
  {
    if ( action )
    {
      epSearch->flags |= eEP_AllowMatch;
    }
    else
    {
      epSearch->flags &= (eEP_AllowMatch ^ 0xFFFF);
    }
    return ( TRUE );
  }
  else
    return ( FALSE );
}

uint8 afNumEndPoints( void )
{
  epList_t *epSearch;
  uint8 endpoints;

  // Start at the beginning
  epSearch = epList;
  endpoints = 0;

  while ( epSearch )
  {
    endpoints++;
    epSearch = epSearch->nextDesc;
  }

  return ( endpoints );
}

void afEndPoints( uint8 *epBuf, uint8 skipZDO )
{
  epList_t *epSearch;
  uint8 endPoint;

  // Start at the beginning
  epSearch = epList;

  while ( epSearch )
  {
    endPoint = epSearch->epDesc->endPoint;

    if ( !skipZDO || endPoint != 0 )
      *epBuf++ = endPoint;

    epSearch = epSearch->nextDesc;
  }
}

void afCopyAddress( afAddrType_t *afAddr, zAddrType_t *zAddr )
{
  afAddr->addrMode = (afAddrMode_t)zAddr->addrMode;
  if ( zAddr->addrMode == Addr64Bit )
  {
    (void)osal_cpyExtAddr( afAddr->addr.extAddr, zAddr->addr.extAddr );
  }
  else
  {
    afAddr->addr.shortAddr = zAddr->addr.shortAddr;
  }

  // Since zAddrType_t has no INTER-PAN information, set the panId member to zero.
  afAddr->panId = 0;
}

void afAPSF_ConfigGet(uint8 endPoint, afAPSF_Config_t *pCfg)
{
  epList_t *pList = afFindEndPointDescList(endPoint);

  if (pList == NULL)
  {
    pCfg->frameDelay = APSF_DEFAULT_INTERFRAME_DELAY;
    pCfg->windowSize = APSF_DEFAULT_WINDOW_SIZE;
  }
  else
  {
    (void)osal_memcpy(pCfg, &pList->apsfCfg, sizeof(afAPSF_Config_t));
  }
}

afStatus_t afAPSF_ConfigSet(uint8 endPoint, afAPSF_Config_t *pCfg)
{
  epList_t *pList = afFindEndPointDescList(endPoint);

  if (pList == NULL)
  {
    return afStatus_INVALID_PARAMETER;
  }

  (void)osal_memcpy(&pList->apsfCfg, pCfg, sizeof(afAPSF_Config_t));
  return afStatus_SUCCESS;
}

AF.h

#ifndef AF_H
#define AF_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "ZComDef.h"
#include "nwk.h"
#include "APSMEDE.h"


#define AF_BROADCAST_ENDPOINT              0xFF

#define AF_PREPROCESS                      0x04   // Will force APS to callback to preprocess before calling NWK layer
#define AF_LIMIT_CONCENTRATOR              0x08
#define AF_ACK_REQUEST                     0x10
#define AF_DISCV_ROUTE                     0x20   // This option is no longer used, and will be taken out later
#define AF_EN_SECURITY                     0x40
#define AF_SKIP_ROUTING                    0x80

// Backwards support for afAddOrSendMessage / afFillAndSendMessage.
#define AF_TX_OPTIONS_NONE                 0
#define AF_MSG_ACK_REQUEST                 AF_ACK_REQUEST

// Default Radius Count value
#define AF_DEFAULT_RADIUS                  DEF_NWK_RADIUS

#define AF_MAX_USER_DESCRIPTOR_LEN         16
#define AF_USER_DESCRIPTOR_FILL          0x20
typedef struct
{
  uint8 len;     // Length of string descriptor
  uint8 desc[AF_MAX_USER_DESCRIPTOR_LEN];
} UserDescriptorFormat_t;

// Node Logical Types
#define NODETYPE_COORDINATOR    0x00
#define NODETYPE_ROUTER         0x01
#define NODETYPE_DEVICE         0x02

// Node Frequency Band - bit map
#define NODEFREQ_800            0x01    // 868 - 868.6 MHz
#define NODEFREQ_900            0x04    // 902 - 928 MHz
#define NODEFREQ_2400           0x08    // 2400 - 2483.5 MHz

// Node MAC Capabilities - bit map
//   Use CAPINFO_ALTPANCOORD, CAPINFO_DEVICETYPE_FFD,
//       CAPINFO_DEVICETYPE_RFD, CAPINFO_POWER_AC,
//       and CAPINFO_RCVR_ON_IDLE from NLMEDE.h

// Node Descriptor format structure
typedef struct
{
  uint8 LogicalType:3;
  uint8 ComplexDescAvail:1;  /* AF_V1_SUPPORT - reserved bit. */
  uint8 UserDescAvail:1;     /* AF_V1_SUPPORT - reserved bit. */
  uint8 Reserved:3;
  uint8 APSFlags:3;
  uint8 FrequencyBand:5;
  uint8 CapabilityFlags;
  uint8 ManufacturerCode[2];
  uint8 MaxBufferSize;
  uint8 MaxInTransferSize[2];
  uint16 ServerMask;
  uint8 MaxOutTransferSize[2];
  uint8 DescriptorCapability;
} NodeDescriptorFormat_t;

// Bit masks for the ServerMask.
#define PRIM_TRUST_CENTER  0x01
#define BKUP_TRUST_CENTER  0x02
#define PRIM_BIND_TABLE    0x04
#define BKUP_BIND_TABLE    0x08
#define PRIM_DISC_TABLE    0x10
#define BKUP_DISC_TABLE    0x20
#define NETWORK_MANAGER    0x40

// Node Current Power Modes (CURPWR)
// Receiver permanently on or sync with coordinator beacon.
#define NODECURPWR_RCVR_ALWAYS_ON   0x00
// Receiver automatically comes on periodically as defined by the
// Node Power Descriptor.
#define NODECURPWR_RCVR_AUTO        0x01
// Receiver comes on when simulated, eg by a user pressing a button.
#define NODECURPWR_RCVR_STIM        0x02

// Node Available Power Sources (AVAILPWR) - bit map
//   Can be used for AvailablePowerSources or CurrentPowerSource
#define NODEAVAILPWR_MAINS          0x01  // Constant (Mains) power
#define NODEAVAILPWR_RECHARGE       0x02  // Rechargeable Battery
#define NODEAVAILPWR_DISPOSE        0x04  // Disposable Battery

// Power Level
#define NODEPOWER_LEVEL_CRITICAL    0x00  // Critical
#define NODEPOWER_LEVEL_33          0x04  // 33%
#define NODEPOWER_LEVEL_66          0x08  // 66%
#define NODEPOWER_LEVEL_100         0x0C  // 100%

// Node Power Descriptor format structure
typedef struct
{
  unsigned int PowerMode:4;
  unsigned int AvailablePowerSources:4;
  unsigned int CurrentPowerSource:4;
  unsigned int CurrentPowerSourceLevel:4;
} NodePowerDescriptorFormat_t;

// AppDevVer values
#define APPDEVVER_1               0x01

// AF_V1_SUPPORT AppFlags - bit map
#define APPFLAG_NONE                0x00  // Backwards compatibility to AF_V1.

// AF-AppFlags - bit map
#define AF_APPFLAG_NONE             0x00
#define AF_APPFLAG_COMPLEXDESC      0x01  // Complex Descriptor Available
#define AF_APPFLAG_USERDESC         0x02  // User Descriptor Available

typedef uint16  cId_t;
// Simple Description Format Structure
typedef struct
{
  uint8          EndPoint;
  uint16         AppProfId;
  uint16         AppDeviceId;
  uint8          AppDevVer:4;
  uint8          Reserved:4;             // AF_V1_SUPPORT uses for AppFlags:4.
  uint8          AppNumInClusters;
  cId_t         *pAppInClusterList;
  uint8          AppNumOutClusters;
  cId_t         *pAppOutClusterList;
} SimpleDescriptionFormat_t;



// Frame Types
#define FRAMETYPE_KVP          0x01     // 0001
#define FRAMETYPE_MSG          0x02     // 0010

#define ERRORCODE_SUCCESS               0x00

#define AF_HDR_KVP_MAX_LEN   0x08  // Max possible AF KVP header.
#define AF_HDR_V1_0_MAX_LEN  0x03  // Max possible AF Ver 1.0 header.
#define AF_HDR_V1_1_MAX_LEN  0x00  // Max possible AF Ver 1.1 header.

// Generalized MSG Command Format
typedef struct
{
  uint8   TransSeqNumber;
  uint16  DataLength;              // Number of bytes in TransData
  uint8  *Data;
} afMSGCommandFormat_t;

typedef enum
{
  noLatencyReqs,
  fastBeacons,
  slowBeacons
} afNetworkLatencyReq_t;

typedef enum
{
  afAddrNotPresent = AddrNotPresent,
  afAddr16Bit      = Addr16Bit,
  afAddr64Bit      = Addr64Bit,
  afAddrGroup      = AddrGroup,
  afAddrBroadcast  = AddrBroadcast
} afAddrMode_t;

typedef struct
{
  union
  {
    uint16      shortAddr;
    ZLongAddr_t extAddr;
  } addr;
  afAddrMode_t addrMode;
  uint8 endPoint;
  uint16 panId;  // used for the INTER_PAN feature
} afAddrType_t;


typedef struct
{
  osal_event_hdr_t hdr;     /* OSAL Message header */
  uint16 groupId;           /* Message's group ID - 0 if not set */
  uint16 clusterId;         /* Message's cluster ID */
  afAddrType_t srcAddr;     /* Source Address, if endpoint is STUBAPS_INTER_PAN_EP,
                               it's an InterPAN message */
  uint16 macDestAddr;       /* MAC header destination short address */
  uint8 endPoint;           /* destination endpoint */
  uint8 wasBroadcast;       /* TRUE if network destination was a broadcast address */
  uint8 LinkQuality;        /* The link quality of the received data frame */
  uint8 correlation;        /* The raw correlation value of the received data frame */
  int8  rssi;               /* The received RF power in units dBm */
  uint8 SecurityUse;        /* deprecated */
  uint32 timestamp;         /* receipt timestamp from MAC */
  uint8 nwkSeqNum;          /* network header frame sequence number */
  afMSGCommandFormat_t cmd; /* Application Data */
} afIncomingMSGPacket_t;

typedef struct
{
  osal_event_hdr_t hdr;
  uint8 endpoint;
  uint8 transID;
} afDataConfirm_t;

// Endpoint Table - this table is the device description
// or application registration.
// There will be one entry in this table for every
// endpoint defined.
typedef struct
{
  uint8 endPoint;
  uint8 *task_id;  // Pointer to location of the Application task ID.
  SimpleDescriptionFormat_t *simpleDesc;
  afNetworkLatencyReq_t latencyReq;
} endPointDesc_t;

// Typedef for callback function to retrieve an endpoints
//   descriptors, contained in the endpoint descriptor.
//   This will allow an application to dynamically change
//   the descriptor and not use the RAM/ROM.
typedef void *(*pDescCB)( uint8 type, uint8 endpoint );

// Descriptor types used in the above callback
#define AF_DESCRIPTOR_SIMPLE            1
#define AF_DESCRIPTOR_PROFILE_ID        2

// Bit definitions for epList_t flags.
typedef enum
{
  eEP_AllowMatch = 1,
  eEP_NotUsed
} eEP_Flags;

typedef struct {
  uint8 frameDelay;
  uint8 windowSize;
} afAPSF_Config_t;

typedef struct _epList_t {
  struct _epList_t *nextDesc;
  endPointDesc_t *epDesc;
  pDescCB  pfnDescCB;     // Don't use if this function pointer is NULL.
  afAPSF_Config_t apsfCfg;
  eEP_Flags flags;
} epList_t;

#define afStatus_SUCCESS            ZSuccess           /* 0x00 */
#define afStatus_FAILED             ZFailure           /* 0x01 */
#define afStatus_INVALID_PARAMETER  ZInvalidParameter  /* 0x02 */
#define afStatus_MEM_FAIL           ZMemError          /* 0x10 */
#define afStatus_NO_ROUTE           ZNwkNoRoute        /* 0xCD */

typedef ZStatus_t afStatus_t;

typedef struct
{
  uint8              kvp;
  APSDE_DataReqMTU_t aps;
} afDataReqMTU_t;

extern epList_t *epList;

  //extern void afInit( void );
  #define afInit()  // No work to do for now.


  extern epList_t *afRegisterExtended( endPointDesc_t *epDesc, pDescCB descFn );

  extern afStatus_t afRegister( endPointDesc_t *epDesc );

  extern afStatus_t afDelete( uint8 EndPoint );

  extern void afDataConfirm( uint8 endPoint, uint8 transID, ZStatus_t status );

  extern void afIncomingData( aps_FrameFormat_t *aff, zAddrType_t *SrcAddress, uint16 SrcPanId,
                       NLDE_Signal_t *sig, uint8 nwkSeqNum, uint8 SecurityUse, uint32 timestamp );

  afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP,
                             uint16 cID, uint16 len, uint8 *buf, uint8 *transID,
                             uint8 options, uint8 radius );


afStatus_t AF_DataRequestSrcRtg( afAddrType_t *dstAddr, endPointDesc_t *srcEP,
                           uint16 cID, uint16 len, uint8 *buf, uint8 *transID,
                           uint8 options, uint8 radius, uint8 relayCnt,
                           uint16* pRelayList );


  extern endPointDesc_t *afFindEndPointDesc( uint8 endPoint );

  extern uint8 afFindSimpleDesc( SimpleDescriptionFormat_t **ppDesc, uint8 EP );

  extern uint8 afDataReqMTU( afDataReqMTU_t* fields );


  extern uint8 afGetMatch( uint8 ep );

  extern uint8 afSetMatch( uint8 ep, uint8 action );

  extern uint8 afNumEndPoints( void );

  extern void afEndPoints( uint8 *epBuf, uint8 skipZDO );

extern void afCopyAddress (afAddrType_t *afAddr, zAddrType_t *zAddr);

void afAPSF_ConfigGet(uint8 endPoint, afAPSF_Config_t *pCfg);

afStatus_t afAPSF_ConfigSet(uint8 endPoint, afAPSF_Config_t *pCfg);

#ifdef __cplusplus
}
#endif
#endif

Security(安全层)

ssp.h

#ifndef SSP_H
#define SSP_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "ZComDef.h"

#define SSP_APPLY  0
#define SSP_REMOVE 1

// Auxiliary header field lengths
#define FRAME_COUNTER_LEN 4

#define SEC_KEY_LEN  16  // 128/8 octets (128-bit key is standard for ZigBee)

// Security Key Indentifiers
#define SEC_KEYID_LINK      0x00
#define SEC_KEYID_NWK       0x01
#define SEC_KEYID_TRANSPORT 0x02
#define SEC_KEYID_LOAD      0x03

// Security Levels
#define SEC_MASK        0x07
#define SEC_NONE        0x00
#define SEC_MIC_32      0x01
#define SEC_MIC_64      0x02

#define SEC_MIC_128     0x03
#define SEC_ENC         0x04
#define SEC_ENC_MIC_32  0x05
#define SEC_ENC_MIC_64  0x06
#define SEC_ENC_MIC_128 0x07

// Key types
#define KEY_TYPE_TC_MASTER  0   // Trust Center Master Key
#define KEY_TYPE_NWK        1   // Standard Network Key
#define KEY_TYPE_APP_MASTER 2   // Application Master Key
#define KEY_TYPE_APP_LINK   3   // Application Link Key
#define KEY_TYPE_TC_LINK    4   // Trust Center Link Key
#define KEY_TYPE_NWK_HIGH   5   // High Security Network Key

#define SSP_AUXHDR_CTRL      0
#define SSP_AUXHDR_FRAMECNTR 1

#define SSP_AUXHDR_KEYID_MASK     0x03
#define SSP_AUXHDR_KEYID_SHIFT    3
#define SSP_AUXHDR_EXTNONCE_SHIFT 5
#define SSP_AUXHDR_EXTNONCE_BIT   0x01
#define SSP_AUXHDR_LEVEL_MASK     0x07

#define SSP_AUXHDR_MIN_LEN    5
#define SSP_AUXHDR_SEQNUM_LEN 1
#define SSP_AUXHDR_EXT_LEN ( SSP_AUXHDR_MIN_LEN + Z_EXTADDR_LEN )
#define SSP_AUXHDR_NWK_LEN ( SSP_AUXHDR_EXT_LEN + SSP_AUXHDR_SEQNUM_LEN  )

#define SSP_MIC_LEN_MAX 16

#define SSP_NONCE_LEN 13

#define SSP_TEXT_LEN 4

// SSP_MacTagData_t::type
#define SSP_MAC_TAGS_SKKE 0
#define SSP_MAC_TAGS_EA   1

// Error value used when security key NV ID is not available
#define SEC_NO_KEY_NV_ID        0


typedef struct
{
  uint8 keySeqNum;
  uint8 key[SEC_KEY_LEN];
} nwkKeyDesc;

typedef struct
{
  nwkKeyDesc  active;
  uint32      frameCounter;
} nwkActiveKeyItems;

typedef struct
{
  uint32 inFrmCntr;
  uint32 outFrmCntr;
  uint8   masterKey[SEC_KEY_LEN];     // optional!!
  uint8   linkKey[SEC_KEY_LEN];
  uint8   partnerDevice[Z_EXTADDR_LEN];
} linkKeyDesc;

typedef struct
{
  uint8 hdrLen;
  uint8 auxLen;
  uint8 msgLen;
  uint8 secLevel;
  uint8 keyId;
  uint32 frameCtr;
  uint8 *key;
} ssp_ctx;

typedef struct
{
  uint8* initExtAddr;
  uint8* rspExtAddr;
  uint8* key;
  uint8* qeu;
  uint8* qev;
  uint8* text1;
  uint8* text2;
  uint8* tag1;
  uint8* tag2;
  uint8* linkKey;
  uint8  type;
} SSP_MacTagData_t;

typedef struct
{
  uint8  dir;
  uint8  secLevel;
  uint8  hdrLen;
  uint8  sduLen;   //service data unit length
  uint8* pdu;      //protocol data unit
  uint8  extAddr[Z_EXTADDR_LEN];
  uint8  keyID;
  uint16 keyNvId; // NV ID of key: NWK, TCLK or APS
  uint8  keySeqNum;
  uint32 frmCntr;
  uint8  auxLen;
  uint8  micLen;
} SSP_Info_t;

extern uint32 nwkFrameCounter;

extern void SSP_Init( void );

extern void SSP_ParseAuxHdr( SSP_Info_t* si );

extern ZStatus_t SSP_Process( SSP_Info_t* si );

extern ZStatus_t SSP_GetMacTags( SSP_MacTagData_t* data );

extern void SSP_GetTrueRand( uint8 len, uint8 *rand );

extern ZStatus_t SSP_GetTrueRandAES( uint8 len, uint8 *rand );

extern void SSP_StoreRandomSeedNV( uint8 *pSeed );

extern void SSP_ReadNwkActiveKey( nwkActiveKeyItems *items );

extern uint16 SSP_GetNwkKey( uint8 seqNum );

extern ZStatus_t SSP_NwkSecurity(uint8 ed_flag, uint8 *msg, uint8 hdrLen, uint8 nsduLen);

extern void SSP_UpdateNwkKey( uint8 *key, uint8 keySeqNum );

extern void SSP_SwitchNwkKey( uint8 seqNum );

extern void SSP_BuildNonce( uint8 *addr, uint32 frameCntr, uint8 secCtrl, uint8 *nonce );

extern uint8 SSP_GetMicLen( uint8 securityLevel );

#ifdef __cplusplus
}
#endif

#endif /* SSP_H */

ssp.hash.h

#ifndef SSP_HASH_H
#define SSP_HASH_H

#ifdef __cplusplus
extern "C"
{
#endif

#include  "ssp.h"


//void SSP_KeyedHash (uint8 *, uint16, uint8 *, uint8 *);
void sspMMOHash (uint8 *, uint8, uint8 *, uint16, uint8 *);
void SSP_KeyedHash (uint8 *M, uint16 bitlen, uint8 *AesKey, uint8 *Cstate);

#ifdef __cplusplus
}
#endif

#endif /* SSP_HASH_H */

Serives(地址处理函)

saddr.c

#include "hal_types.h"
#include "OSAL.h"
#include "saddr.h"

bool sAddrCmp(const sAddr_t *pAddr1, const sAddr_t *pAddr2)
{
  if (pAddr1->addrMode != pAddr2->addrMode)
  {
    return FALSE;
  }
  else if (pAddr1->addrMode == SADDR_MODE_NONE)
  {
    return FALSE;
  }
  else if (pAddr1->addrMode == SADDR_MODE_SHORT)
  {
    return (bool) (pAddr1->addr.shortAddr == pAddr2->addr.shortAddr);
  }
  else if (pAddr1->addrMode == SADDR_MODE_EXT)
  {
    return (sAddrExtCmp(pAddr1->addr.extAddr, pAddr2->addr.extAddr));
  }
  else
  {
    return FALSE;
  }
}


bool sAddrIden(const sAddr_t *pAddr1, const sAddr_t *pAddr2)
{
  // first check if the address modes are the same
  if (pAddr1->addrMode != pAddr2->addrMode)
  {
    // no, so no point in comparing any further
    return FALSE;
  }
  // the address modes are the same; check if there is no address
  else if (pAddr1->addrMode == SADDR_MODE_NONE)
  {
    // no address, so no need to compare any further as both addresses have the
    // same address mode but no address, so they are identical
    return TRUE;
  }
  // there's an address; check if it is short
  else if (pAddr1->addrMode == SADDR_MODE_SHORT)
  {
    // compare short addresses
    return (bool) (pAddr1->addr.shortAddr == pAddr2->addr.shortAddr);
  }
  // there's an address; check if it is extended
  else if (pAddr1->addrMode == SADDR_MODE_EXT)
  {
    // compare extended addresses
    return (sAddrExtCmp(pAddr1->addr.extAddr, pAddr2->addr.extAddr));
  }
  else // unknown error
  {
    return FALSE;
  }
}

void sAddrCpy(sAddr_t *pDest, const sAddr_t *pSrc)
{
  pDest->addrMode = pSrc->addrMode;

  if (pDest->addrMode == SADDR_MODE_EXT)
  {
    sAddrExtCpy(pDest->addr.extAddr, pSrc->addr.extAddr);
  }
  else
  {
    pDest->addr.shortAddr = pSrc->addr.shortAddr;
  }
}

bool sAddrExtCmp(const uint8 * pAddr1, const uint8 * pAddr2)
{
  uint8 i;

  for (i = SADDR_EXT_LEN; i != 0; i--)
  {
    if (*pAddr1++ != *pAddr2++)
    {
      return FALSE;
    }
  }
  return TRUE;
}

void *sAddrExtCpy(uint8 * pDest, const uint8 * pSrc)
{
  return osal_memcpy(pDest, pSrc, SADDR_EXT_LEN);
}

saddr.h

#ifndef SADDR_H
#define SADDR_H


#ifdef __cplusplus
extern "C" {
#endif

/* Extended address length */
#define SADDR_EXT_LEN   8

/* Address modes */
#define SADDR_MODE_NONE       0       /* Address not present */
#define SADDR_MODE_SHORT      2       /* Short address */
#define SADDR_MODE_EXT        3       /* Extended address */

/* Extended address */
typedef uint8 sAddrExt_t[SADDR_EXT_LEN];

/* Combined short/extended device address */
typedef struct
{
  union
  {
    uint16      shortAddr;    /* Short address */
    sAddrExt_t  extAddr;      /* Extended address */
  } addr;
  uint8         addrMode;     /* Address mode */
} sAddr_t;

extern bool sAddrCmp(const sAddr_t *pAddr1, const sAddr_t *pAddr2);

extern bool sAddrIden(const sAddr_t *pAddr1, const sAddr_t *pAddr2);

extern void sAddrCpy(sAddr_t *pDest, const sAddr_t *pSrc);

extern bool sAddrExtCmp(const uint8 * pAddr1, const uint8 * pAddr2);

void *sAddrExtCpy(uint8 * pDest, const uint8 * pSrc);

#ifdef __cplusplus
}
#endif

#endif /* SADDR_H */

Tools(工程配置)

f8w2530.xcl

另外说明

f8wConfig.cfg

-DZIGBEEPRO

/* Set to 0 for no security, otherwise non-0 */
-DSECURE=0
-DZG_SECURE_DYNAMIC=0

/* Enable the Reflector */
-DREFLECTOR

/* Default channel is Channel 11 - 0x0B */
// Channels are defined in the following:
//         0      : 868 MHz     0x00000001
//         1 - 10 : 915 MHz     0x000007FE
//        11 - 26 : 2.4 GHz     0x07FFF800
//
//-DMAX_CHANNELS_868MHZ     0x00000001
//-DMAX_CHANNELS_915MHZ     0x000007FE
//-DMAX_CHANNELS_24GHZ      0x07FFF800
//-DDEFAULT_CHANLIST=0x04000000  // 26 - 0x1A
//-DDEFAULT_CHANLIST=0x02000000  // 25 - 0x19
//-DDEFAULT_CHANLIST=0x01000000  // 24 - 0x18
//-DDEFAULT_CHANLIST=0x00800000  // 23 - 0x17
//-DDEFAULT_CHANLIST=0x00400000  // 22 - 0x16
//-DDEFAULT_CHANLIST=0x00200000  // 21 - 0x15
//-DDEFAULT_CHANLIST=0x00100000  // 20 - 0x14
//-DDEFAULT_CHANLIST=0x00080000  // 19 - 0x13
//-DDEFAULT_CHANLIST=0x00040000  // 18 - 0x12
//-DDEFAULT_CHANLIST=0x00020000  // 17 - 0x11
//-DDEFAULT_CHANLIST=0x00010000  // 16 - 0x10
//-DDEFAULT_CHANLIST=0x00008000  // 15 - 0x0F
//-DDEFAULT_CHANLIST=0x00004000  // 14 - 0x0E
//-DDEFAULT_CHANLIST=0x00002000  // 13 - 0x0D
//-DDEFAULT_CHANLIST=0x00001000  // 12 - 0x0C
-DDEFAULT_CHANLIST=0x00000800  // 11 - 0x0B

/* Define the default PAN ID.
 *
 * Setting this to a value other than 0xFFFF causes
 * ZDO_COORD to use this value as its PAN ID and
 * Routers and end devices to join PAN with this ID
 */
-DZDAPP_CONFIG_PAN_ID=0xFFF1

/* Minimum number of milliseconds to hold off the start of the device
 * in the network and the minimum delay between joining cycles.
 */
-DNWK_START_DELAY=100

/* Mask for the random joining delay. This value is masked with
 * the return from osal_rand() to get a random delay time for
 * each joining cycle.  This random value is added to NWK_START_DELAY.
 * For example, a value of 0x007F will be a joining delay of 0 to 127
 * milliseconds.
 */
-DEXTENDED_JOINING_RANDOM_MASK=0x007F

/* Minimum number of milliseconds to delay between each beacon request
 * in a joining cycle.
 */
-DBEACON_REQUEST_DELAY=100

-DBEACON_REQ_DELAY_MASK=0x00FF

-DLINK_STATUS_JITTER_MASK=0x007F

/* in seconds; set to 0 to turn off route expiry */
-DROUTE_EXPIRY_TIME=30

-DAPSC_ACK_WAIT_DURATION_POLLED=3000

/*  Default indirect message holding timeout value:
 *  1-65535 (0 -> 65536) X CNT_RTG_TIMER X RTG_TIMER_INTERVAL
 */
-DNWK_INDIRECT_MSG_TIMEOUT=7

/* The number of simultaneous route discoveries in network */
-DMAX_RREQ_ENTRIES=8

/* The maximum number of retries allowed after a transmission failure */
-DAPSC_MAX_FRAME_RETRIES=3

/* Max number of times retry looking for the next hop address of a message */
-DNWK_MAX_DATA_RETRIES=2

-DMAX_POLL_FAILURE_RETRIES=2

/* The number of items in the broadcast table */
-DMAX_BCAST=9

/* The maximum number of groups in the groups table */
-DAPS_MAX_GROUPS=16

/* Number of entries in the regular routing table plus additional
 * entries for route repair
 */
-DMAX_RTG_ENTRIES=40

/* Maximum number of entries in the Binding table. */
-DNWK_MAX_BINDING_ENTRIES=4

/* Maximum number of cluster IDs for each binding table entry.
 * Note that any value other than the default value may cause a
 * compilation warning but Device Binding will function correctly.
 */
-DMAX_BINDING_CLUSTER_IDS=4

/* Default security key. */
-DDEFAULT_KEY="{0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0D}"

/* Reset when ASSERT occurs, otherwise flash LEDs */
//-DASSERT_RESET

/* Set the MAC MAX Frame Size (802.15.4 default is 102) */
-DMAC_MAX_FRAME_SIZE=116

/* Minimum transmissions attempted for Channel Interference detection,
 * Frequency Agility can be disabled by setting this parameter to zero.
 */
-DZDNWKMGR_MIN_TRANSMISSIONS=20

/* Compiler keywords */
-DCONST="const __code"
-DGENERIC=__generic

-DRFD_RCVC_ALWAYS_ON=FALSE

/* The number of milliseconds to wait between data request polls to the coordinator. */
-DPOLL_RATE=1000

-DQUEUED_POLL_RATE=100

-DRESPONSE_POLL_RATE=100

-DREJOIN_POLL_RATE=440

f8wCoord.cfg

-DCPU32MHZ                         // CC2530s Run at 32MHz
-DROOT=__near_func                 // MAC/ZMAC code in NEAR

/* MAC Settings */
-DMAC_CFG_APP_PENDING_QUEUE=TRUE
-DMAC_CFG_TX_DATA_MAX=5
-DMAC_CFG_TX_MAX=8
-DMAC_CFG_RX_MAX=5

/* Coordinator Settings */
-DZDO_COORDINATOR                  // Coordinator Functions
-DRTR_NWK                          // Router Functions

f8wEndev.cfg

-DCPU32MHZ                    // CC2530s Run at 32MHz
-DROOT=__near_func            // MAC/ZMAC code in NEAR

/* MAC Settings */
-DMAC_CFG_TX_DATA_MAX=3
-DMAC_CFG_TX_MAX=6
-DMAC_CFG_RX_MAX=3


f8wRounter.cfg

-DCPU32MHZ                         // CC2530s Run at 32MHz
-DROOT=__near_func                 // MAC/ZMAC code in NEAR

/* MAC Settings */
-DMAC_CFG_APP_PENDING_QUEUE=TRUE
-DMAC_CFG_TX_DATA_MAX=5
-DMAC_CFG_TX_MAX=8
-DMAC_CFG_RX_MAX=5

/* Router Settings */
-DRTR_NWK                          // Router Functions

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃橘子的橘猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值