/**
* 
* * $Rev: 51 $
* Filename:      sensor_demo_app.c
* $Author: Morten & Suyash $
* $Date: 2010-06-11 10:17:22 -0700  $
* Description: Public interface file for the ZNP Sample Application.
*
* YOU ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT WARRANTY 
* OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, 
* TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL TEXAS INSTRUMENTS 
* OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, 
* BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
* INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, 
* LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY 
* CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
*/
#include "hal.h"
#include "application_configuration.h"
#include "znp_interface_spi.h"
#include "simple_api.h"
#include "hal_defs.h"
#include "Sensor_demo_app.h"
#include "mt.h"


extern unsigned char znpBuf[100];

typedef enum {
  appIniting,
  appWaiting,
  appJoining,
  appJoinWaiting,
  appBinding,
  appBindWaiting,
  appRunning
} AppState;  /* Valid appState values.*/


/*Global Variables*/
uint16 TACCR0_INIT;
uint8 appFlags;
int ZNPNwkState;
uint16 ZNPNwkAddr;
extern signed int znpResult;                    
extern unsigned char sequenceNumber;
static uint8 NV_RESTORE_START;


/*Local Variables*/
__no_init volatile int tempOffset @ 0x10F4;  /* Temperature offset set at production. */
volatile uint8 halSwCnt;
static AppState appState;
#if APP_DATA_CNF
static uint8 appMsgRtry;
#endif
static uint8 srceReport[SRCE_REPORT_SZ];

/* Local Functions*/

/* Triggered by HAL flags.*/
static void appExec(void);
static void appBtnPress(void);

/* Helper functions for appExec()..*/
static void appJoinFail(void);

/* Helper functions for appBtnPress()..*/
static void appStartRequest(uint8 rtrType);
static void appToggleJoin(void);

/* Triggered by ZNP flags or ZNP response..*/
static void appReset(void);
static void appStart(void);
#if APP_DATA_CNF
static void appDataCnf(void);
#else
#define appDataCnf()
#endif
static void appSinkData(void);
static void appSrceBind(void);
static void appSrceData(void);
#if APP_BLINK_LEDS
static void appLedBlink(uint8 led);
#else
#define appLedBlink(led)
#endif


/* appInit This function performs the host application initialization.
appInit performs a hard reset on the CC2530ZNP and enables the interrupts
for program to accept and process hardware interrupts (button press, timer, adc, etc)
input parameters None. output parameters None. @return None.
 */
void appInit(void)
{
    #if APP_BLINK_LEDS
      /*Setup the LED's to blink at 1-Hz.*/
      halTimerSet(HAL_IDX_TIMER_LED, APP_BLINK_INTERVAL, HAL_TIMER_AUTO);
    #endif
      HAL_ENABLE_INTERRUPTS();
}

/*
appExecHal This function is the application executive for HAL(hardware) events.
input parameters None. output parameters None. 
@return TRUE if a HAL event was processed; FALSE otherwise.
*/

uint16 appExecHal(void)
{
  uint16 event = HAL_EVT_NONE;
  halIntState_t s;
   
  if (halEventFlags & HAL_EVT_TIMER_LED)
  {
    event = HAL_EVT_TIMER_LED;
    appLedBlink(APP_STAT_LED);
  }
  
  else if (halEventFlags & HAL_EVT_TIMER_BTN)
  {
    /*Program enters here after time  = (APP_BTN_INTERVAL seconds) have expired after first button press*/
    event = HAL_EVT_TIMER_BTN;
    appBtnPress();
  }
  else if (halEventFlags & HAL_EVT_TIMER_APP)
  {
    event = HAL_EVT_TIMER_APP;
    appExec();
  }
  else if (halEventFlags & HAL_EVT_BTN_PRESS)
  {
    /*Program enters here after first button press and starts the timer for APP_BTN_INTERVAL 
    (currently 2) seconds. Now number of button press in configured time interval will determine the type 
    of device (Source (Router or End Device) or Sink (Coordinator))
    And LED blinking is turned off */
    event = HAL_EVT_BTN_PRESS;
    /* wait for 2 sec and count the number of button presses in this time*/
    halTimerSet(HAL_IDX_TIMER_BTN, APP_BTN_INTERVAL, 0);
    /* Immediately turn off LEDs when user starts a join process.*/
    if (appState == appWaiting)
    {
      /* Stop the LED blink during joining. */
      halTimerSet(HAL_IDX_TIMER_LED, 0, 0);  
      HAL_TURN_OFF_GRN();
      HAL_TURN_OFF_RED();
    }
  }
  else if (halEventFlags & HAL_EVT_ADC)
  {
    event = HAL_EVT_ADC;
    appSrceData();
  }

  #if HOST_MT
    else if (halEventFlags & HAL_EVT_MT_RX_RDY)
    {
      if (mtRx())
      {
        event = HAL_EVT_MT_RX_RDY;
      }
    }
  #endif
 
  /*IF the button is pressed for more than 7-8seconds the ZNP and MSP will Reset with ZNP with clear
  configuration and state*/
  else if( halEventFlags & HAL_EVT_ZNP_RESET )
  {
    /*Set NV Flags to clear ZNP configuration and state on next Start and then reset ZNP*/
    setStartupOptions(STARTOPT_CLEAR_CONFIG + STARTOPT_CLEAR_STATE);
    znpReset();
    /*illegal write (without watchdog password) to watchdog timer will cause MSP430 to reset*/
    WDTCTL = WDTHOLD; 
  }

  /* Since HAL event flags are set at the interrupt level, they must only be cleared within
   * a critical section.
   */
  if (event != ZNP_EVT_NONE)
  {
    HAL_ENTER_CRITICAL_SECTION(s);
    event = halEventFlags & event;
    halEventFlags ^= event;
    HAL_EXIT_CRITICAL_SECTION(s);
    return TRUE;
  }
  
  return FALSE;
}

/*appExecHost This function is the APP executive for ZNP events.
input parameters None. output parameters None.@return 
TRUE if a ZNP event was processed; FALSE otherwise.
*/
uint16 appExecHost(void)
{
  uint16 event = ZNP_EVT_NONE;

  znpPoll();

  if (ZNPEvtFlags & ZNP_SYS_RESET_IND)
  {
    event = ZNP_SYS_RESET_IND;
    appReset();
  }
  else if (ZNPEvtFlags & ZNP_START_CNF)
  {
    
    event = ZNP_START_CNF;
   
    if (appState == appJoining)
    {
      appStart();
    }
    
  }                               
  else if (ZNPEvtFlags & ZNP_BIND_CNF)
  {
    event = ZNP_BIND_CNF;
  
    if (APP_SRCE)
    {
      if(ZNP_NWK_RTR)
      {
        /*send dummy temperature and voltage data to sensor monitor demo GUI one time to recognize the device as Router*/
        srceReport[SRCE_REPORT_BUSV] = 0xFF;
        srceReport[SRCE_REPORT_TEMP] = 0xFF;
        /*This send will wait for APS ACK*/
        sendData(ZB_BINDING_ADDR,SRCE_REPORT_ID,srceReport,4); 
      }
 
      /* Setup an auto-repeating timer to send periodic status reports OTA. */
      halTimerSet(HAL_IDX_TIMER_APP, APP_REPORT_INTERVAL, HAL_TIMER_AUTO);
      appState = appRunning;
      
      /* But send a report immediately from here to reduce latency of 1st report from a new node. */
      appSrceData();
      }
  }
  else if (ZNPEvtFlags & ZNP_SEND_DATA_CNF)
  {
    event = ZNP_SEND_DATA_CNF;
    
    if (APP_SRCE)
    {
      appDataCnf();
    }
  }
  else if (ZNPEvtFlags & ZNP_RCV_DATA_IND)
  {
    event = ZNP_RCV_DATA_IND;
    appSinkData();
  }
  
  if (event != ZNP_EVT_NONE)
  {
    event = ZNPEvtFlags & event;
    ZNPEvtFlags ^= event;
    return TRUE;
  }
 
  return FALSE;
}

/* appExec This function is the APP executive run by a periodic timer event.
input parameters None. output parameters None.@return None.
*/
static void appExec(void)
{
  switch (appState)
  {
  case appIniting:
  case appWaiting:
    /* Not expected in this state, so just stop the timer in case it is auto-repeating. */
    halTimerSet(HAL_IDX_TIMER_APP, 0, 0);
    break;

  case appJoining:
    /* Attempting to join did not succeed within the allowed APP_NEW_JOIN_TIME.*/
    appJoinFail();
    break;

  case appJoinWaiting:
    /* Set rtrType=False since only an RFD uses this state (to sleep and retry joining.) */
    appStartRequest(0);
    break;

  case appBinding:
    halTimerSet(HAL_IDX_TIMER_APP, APP_BIND_WAIT, 0);
    appState = appBindWaiting;
    break;

  case appBindWaiting:
    appSrceBind();
    break;

  case appRunning:
    if (APP_SRCE)
    {
      if (appFlags & appSendingF)
      {
        /*If ack was not recieved after sending the data 
        Application sets the appSendingF flag
        appDataCnf checks if acknowledgement has been received
        If not it tries to resend the data 
        after set number of retires, device enters the binding state where it 
        tries to bind to the sink again
        */
        appDataCnf();
      }
      else if (appFlags & appSetPollF)
      {
       setPollRate(APP_POLL_INTERVAL);  /*In this application, disabling polling to save battery power on end device*/
       /*When an end-device sends a data packet, it can poll again with a shorter duration, specified by APP_RESPONSE_POLL parameter, 
       if the application is expecting to receive an application level packet in response.
       Developers are recommended to choose this value carefully, depending on the application requirement
       Please refer to the ZNP Interface Specification for more details, if not expecting an application level packet it ca be set to zero*/
       setResponsePollRate(APP_RESPONSE_POLL);  
       znpReset();       
       
      }
     else
      {
        /*Read temperature and voltage data and send it to the sink along with parents Short address*/
        appSrceData();
      }
    }
    break;
  }
}

/*appBtnPress This function acts on a button press. 
Depending on the state of the application either appWaiting or appRunning action is taken in all other states no action is taken.
1. if appWaiting - Then after 2 seconds interval has passed after the first button press the application calls this function to 
call appStartRequest function to start/configure the device and start.
2. While appRunning - if the device is Router or Coordinator button press will toggle the permission to allow a device to join or not
input parameters None. output parameters None. @return None.
*/
static void appBtnPress(void)
{
  switch (appState)
  {
  case appIniting:
    /* Do not act on a button press in this state which should be only momentary after powerup.*/
    break;
  case appWaiting:
    /*Number of button presses in two seconds is stored in halSwCnt, we check that count and call appStartRequest 
    to start the ZNP as either Router or End-Device. If join as Router fails, we will re-configure the ZNP to be coordinator. If join as
    End device fails, device will go into sleep mode and retry joining after configured time interval*/
    appStartRequest((halSwCnt==1));
    break;
  case appJoining:
  case appJoinWaiting:
  case appBinding:
  case appBindWaiting:
    /* Do not act on a button press in these states.*/
    break;
  case appRunning:
   /*If button is pressed in appRunning State - and device is either coordinator or router
    then toggle the join permissions for the deivce*/
    if (ZNP_NWK_RTR)
    {
      appToggleJoin();
    }
    break;
  }
  /*set halSwCnt as zero*/
  halSwCnt = 0;
}

/* appJoinFail This function executes the specified behaviour when a join attempt fails.
input parameters None. output parameters None.@return None.
*/

static void appJoinFail(void)
{
  getDeviceInformationProperty(DIP_STATE);                                
  ZNPNwkState = znpBuf[SRSP_DIP_VALUE_FIELD];
  
  /*check if device has already joined the network*/
  if (ZNP_NWK_CONN)
  {
   appStart();
   return;
  }
  
  /* If attempting to join as an RFD/End Device fails, the only way to stop it is to reset ZNP.
   * Sleep for SRCE_EXEC_TIME and re-try joining.
  */
  if (appFlags & appLowPwrF)
  {
    /* Stop ZNP attempting to join the network*/
    znpReset();   
    
    appState = appJoinWaiting;
    
    halTimerSet(HAL_IDX_TIMER_APP, APP_JOIN_WAIT, 0);    
   
  }
  /* If attempting to join as an FFD/Router fails, start a new network as a Coordinator.*/
  else  
  {
    
    znpReset();
    
    //sapiRegisterApplication(sinkEP());  
    
    setZigbeeDeviceType(COORDINATOR);
    
    sapiStartApplication(); 
    
    appFlags |= appSinkingF;
   }
}

/* appStartRequest This function acts on a button press.
 * input parameters (number of button press). output parameters None. @return None.
 */
static void appStartRequest(uint8 rtrType)
{

  unsigned char deviceType ;
  if (rtrType)
  {     
    deviceType = ROUTER;
  }
  else 
  {
    deviceType = END_DEVICE;
    appFlags |= (appLowPwrF | appSetPollF);  /* flags set for end device type*/
  }
    
  /*Set ZigBee Device Type */
  setZigbeeDeviceType(deviceType);
  
  /*Register application endpoint for either router or end device*/
  sapiRegisterApplication(srceEP());
  
  /*Start Application*/
  sapiStartApplication();    
  
  /*Change network state to appJoining*/
  appState = appJoining;
  getDeviceInformationProperty(DIP_STATE);
  
  /* The ZNP will try to join indefinitely, so the host is setting a timer in order to take
   * action if the join attempt does not succeed within a reasonable amount of time.
   */
  halTimerSet(HAL_IDX_TIMER_APP, APP_JOIN_TIME, 0);
}


/* appToggleJoin This function acts on a request to toggle the permit join state of the ZNP. 
input parameters None. output parameters None. @return None.
 */
static void appToggleJoin(void)
{
  /* Toggle the "permit joining" of the ZNP and set the LED behavior accordingly. */
  if (appFlags & appPermittingF)  /*if permitting the join currently */
  {
    /*clear application flag to indicate device does not permits join now*/
    appFlags &= ~appPermittingF;
    /*dis-allow join*/
    setJoiningPermissions(ZNPNwkAddr,0);
    /* A Coordinator-Sink device starts blinking the Red LED when not permitting join. */
    if (ZNP_NWK_COOR)
    {
      HAL_TURN_OFF_RED();
    }
    /* A Router-Source device starts blinking the Green LED when not permitting join.*/
    else
    {
      HAL_TURN_OFF_GRN();
    }
    /* Setup the LED blink at 1-Hz. */
    halTimerSet(HAL_IDX_TIMER_LED, APP_BLINK_INTERVAL, HAL_TIMER_AUTO);
  }
  else/*if not permitting the join currently */
  {
    /* Stop the LED blink. */
    halTimerSet(HAL_IDX_TIMER_LED, 0, 0);

    /* A Router-Source device sets the Red LED solid on when permitting join. */
    if (ZNP_NWK_COOR)
    {
      HAL_TURN_ON_RED();
    }
    /* A Router-Source device sets the Green LED solid on when permitting join. */
    else
    {
      HAL_TURN_ON_GRN();
    }
    /*set application flag to indicate device permits join*/
    appFlags |= appPermittingF;
    /*allow join*/
    setJoiningPermissions(ZNPNwkAddr,NO_TIMEOUT);
  }
}

/* appReset This function is the host action on a ZNP reset.
input parameters None. output parameters None. @return None.
*/
static void appReset(void)
{
  /* No previously received indication flag can be valid after the ZNP resets. */
  ZNPIndFlags = 0;

  /* No ZigBee Endpoints (not even the Simple Descriptor) are not stored in the ZNP NV.
   * Therefore, the host must re-register anytime that the ZNP resets.
   */
  if (APP_SRCE)
  {
    /*If device is to be a source - register the srce application end point
    See srceEP() for sinple descriptor of Source End point */
    sapiRegisterApplication(srceEP());
  }
  else
  {
    /*If device is to be a sink - register the srce application end point
    See sinkEP() for sinple descriptor of Sink End point */
    sapiRegisterApplication(sinkEP());
  }
  switch (appState)
  {
  case appIniting:
    {
      setStartupOptions(STARTOPT_CLEAR_CONFIG + STARTOPT_CLEAR_STATE);
      znpReset();
      appState = appWaiting;
    }  
    break;

  case appWaiting:
    /* The last step of the appIniting above was to reset the ZNP. */
    {
      setStartupOptions(STARTOPT_AUTO); /*for next start preserve the configuration parameters and state*/
      setChannel(DEFAULT_CHANNEL);
      setCallbacks(CALLBACKS_ENABLED);   /*application will recieve verbose ZDO response message For example, */
    }
    break;

  case appJoining:
    /* This host application has configured the ZNP as a ZigBee device and then reset it so that
     * the ZNP can re-configure its RAM accordingly and start an auto-join process from powerup.
     * No action other than registering the Endpoint, already done above, is required.
     * The host will receive a join indication from the ZNP or the joining timer will expire.
     */
  case appJoinWaiting:
    /* This host application has configured the ZNP to stop attempting to join so that low power
     * can be entered while waiting to re-try joinin.
     */
    break;

  case appBinding:
   /*If application reset is called in appBinding No action other than re-registering the application end
    points is required*/
    break;
  
  case appBindWaiting:
   /*If application reset is called in appBinding No action other than re-registering the application end
    points is required*/ 
    break;
  
  case appRunning:
     if (appFlags & appSetPollF)
         {/*After setting the poll rate the device resets*/
           /*start the ZNP - the device is End device*/
           sapiStartApplication(); 
           appFlags &= ~appSetPollF;
         }
      HAL_ENABLE_INTERRUPTS();
    break;
  }
}

/*If NV_RESTORE is enabled we check the ZNP NV memory for previous configuration in this application we
chech the value of PAN ID stored in NV, if it is not equal to 0xFFFF then device was started before 
and has network configuration parameters in the NV .We try to start or join the previous network with the stored PAN ID 
*/

void appSync(void)
{
      unsigned char *pan_id;
      char deviceType_t;
    
     /*Read NV */
     deviceType_t = *(getConfigurationParameter(ZCD_NV_DEVICE_TYPE)); 
     pan_id = getConfigurationParameter(ZCD_NV_PANID);
     
     /*Check for PANID in the NV memory of the device */
     if( (*pan_id == 0xFF && *(pan_id+1) == 0xFF ))   
     {
        appInit();
        return;
     }
  
     /*If device was configured earlier and will now join the network using configuration in the NV*/
     if(deviceType_t == COORDINATOR)
     {
         /* flags set for Coordinator-Sink */ 
         appFlags |= appSinkingF;
         /*Register the endpoint*/
         sapiRegisterApplication(sinkEP());
     }
     else if(deviceType_t == ROUTER || deviceType_t == END_DEVICE)
     {
         /*Register the endpoint*/
         sapiRegisterApplication(srceEP());
     }
     
     appState = appJoining;
     NV_RESTORE_START =1;   /*Start using stored NV parameters */
     setCallbacks(CALLBACKS_ENABLED);  
     sapiStartApplication();   
     
}

/*appStart This function is the host application intialization using the ZNP SAPI interface.
input parameters  None. output parameters None. @return None.
 */
static void appStart(void)
{
    
    /*get device's network address*/
    getDeviceInformationProperty(DIP_SHORT_ADDRESS);
    ZNPNwkAddr =(uint16)(znpBuf[SRSP_DIP_VALUE_FIELD]| (uint16)(znpBuf[SRSP_DIP_VALUE_FIELD+1]<<8));
    
    /*get device's network state Coordinator, Router, End Device*/
    getDeviceInformationProperty(DIP_STATE);                                
    ZNPNwkState = znpBuf[SRSP_DIP_VALUE_FIELD];

    #ifdef NV_RESTORE      
        static uint16 panId;
        /*Store PANID in NV Mem for next silent rejoin of the network*/
        getDeviceInformationProperty(DIP_PANID);
        panId = (uint16)(znpBuf[4]| (uint16)(znpBuf[5]<<8));
        setPanId(panId);
    #endif    
        
    /*
    * Find the parent address of the device and send it with the message to coodinator. 
    * Parent address is used by sensor monitor demo Graphical display to 
    * identify how to connect the devices on the Graphical display 
    */
    getDeviceInformationProperty(DIP_PARENT_SHORT_ADDRESS);
    srceReport[SRCE_REPORT_PARENT_ADDR] = znpBuf[SRSP_DIP_VALUE_FIELD];
    srceReport[SRCE_REPORT_PARENT_ADDR+1] = znpBuf[SRSP_DIP_VALUE_FIELD+1];

    /*configure devices according to Source and Sink functions*/
    if (ZNP_NWK_RTR)                /*True if the device is configured as either a router or coordinator */
   {
     appFlags &= ~appPermittingF;   /*disable permitting flag */
     appToggleJoin();               /* This will set permit joining allowed in Router and coordintator after start-up and set LEDs accordingly.*/
     if (!APP_SRCE)                 /*if sink (coordinator)*/
       {
        setallowbind(APP_PMT_BIND); /*Allow binding permamantly */
        appState = appRunning;      /*Now state is appRunning*/
       }
   }
    #if APP_BLINK_LEDS
      else
      {
        /* RFD/End Device type blinks the Green LED.*/
        halTimerSet(HAL_IDX_TIMER_LED, APP_BLINK_INTERVAL, HAL_TIMER_AUTO);
      }
    #endif
    if(APP_SRCE)
    {
       setallowbind(APP_DENY_BIND);    /*Disallow binding feature permamantly on Source devices */
      
       if(NV_RESTORE_START == 0)
       {
         appSrceBind();    
       }
       else
       {
          ZNPIndFlags |= ZNP_BIND_SUCCESS;
          ZNPEvtFlags|= ZNP_BIND_CNF;
       }
    }
}

#if APP_DATA_CNF
/* appDataCnf This function is the host application action upon receiving a message confirmation.
input parameters None. output parameters None. @return None.
*/
static void appDataCnf(void)
{
  if (ZNPIndFlags & ZNP_SEND_SUCCESS)   /*if received Ack */
  {
    ZNPIndFlags &= ~ZNP_SEND_SUCCESS;
    appFlags &= ~appSendingF;
    appLedBlink(APP_DATA_LED);
    if (appFlags & appLowPwrF)
    {
      /* Now RFD sets timer to wake from sleep to send the next report.
       * The FFD just leaves this timer auto-repeating at the APP_REPORT_INTERVAL.
       */
      halTimerSet(HAL_IDX_TIMER_APP, APP_REPORT_INTERVAL, HAL_TIMER_AUTO);
    }
     }
  else if ((appMsgRtry == 0) || (--appMsgRtry == 0))
  {
    /* When a message confirmation fails after APP_RETRY_CNT retries, attempt to re-bind.*/
    appFlags &= ~appSendingF; /*Clear the appFlag */
    appSrceBind();   
  }
  else
  {
    /*This application increaments the sequenceNumber in the sendData function when sending a message,    
    If msg send was unsuccessfull then Decrement the sequenceNumber to keep same msg number in retries*/
    sequenceNumber = sequenceNumber - 1; 
    sendData(ZB_BINDING_ADDR, SRCE_REPORT_ID, srceReport,4);
  }
}
#endif


/* appSinkData This function is the host application to process received data.
input parameters None. output parameters None. @return None.
*/
static void appSinkData(void)
{
  appLedBlink(APP_DATA_LED);
}

/* appSrceBind This function is the host application to request an Endpoint binding.
input parameters None. output parameters None. @return None.
*/
#define Z_EXTADDR_LEN    8
static void appSrceBind(void)
{
  /* IEEE address of the device to establish the binding with. Set the destIEEE to NULL
   * in order to bind with any other device that is in the Allow Binding Mode.
   */
   uint8 destIEEE[Z_EXTADDR_LEN] = { 0, 0, 0, 0, 0, 0, 0, 0 };
   binddevice(TRUE, SRCE_REPORT_ID, destIEEE);   
   halTimerSet(HAL_IDX_TIMER_APP, APP_BIND_TIME, 0);
   appState = appBinding;
}

/* 
   appSrceData This function is the host application to send data.
   Application Reads the temperature, voltage data and ZNP device Parent address. Populates the message array srceReport and sends the message
   input parameters None. output parameters None.@return None.
*/
static void appSrceData(void)
{
  uint16 tmp;
  switch (appFlags & (appTempF | appBusVF))
  {
  case 0:  /* Idle - not reading the ADC.*/
    /* Setup to sample air temperature.*/
    appFlags |= appTempF;
    halReadTemp();
    break;

  case appTempF:  /* Measuring air temperature.*/
    appFlags &= ~appTempF;
    /* oC = ((A10/1024)*1500mV)-986mV)*1/3.55mV = A10*423/1024 - 278*/
    srceReport[SRCE_REPORT_TEMP] = ((halAdcVal - 673) * 423) / 1024;
    if (tempOffset != 0xFFFF)
    {
      srceReport[SRCE_REPORT_TEMP] += tempOffset/10;
    }
    /* Setup to sample bus voltage.*/
    appFlags |= appBusVF;
    halReadBusV();
    break;

  case appBusVF:  /* Measuring bus voltage.*/
    appFlags &= ~appBusVF;
    /* halAdcVal contains measurement of AVcc/2
     * halAdcVal is in range 0 to 1023 indicating voltage from 0 to 1.5V
     * voltage = (halAdcVal*2*1.5)/1023 volts
     * we will multiply by this by 10 to allow units of 0.1 volts
     */
    tmp = (halAdcVal * 30 + 512) / 1024;  /* Convert to units of 0.1V*/
    srceReport[SRCE_REPORT_BUSV] = (uint8)tmp;
            
#if APP_DATA_CNF
    if (APP_SRCE)
    {
      sendData(ZB_BINDING_ADDR,SRCE_REPORT_ID,srceReport,4);  
      appFlags |= appSendingF;
      /* An RFD/End device needs a timer to wake from sleep and poll the ZNP for the ZNP_SEND_DATA_CNF.
       * An FFD/Router or coordinator will always be awake and ready to poll for it.
       */
      if (appFlags & appLowPwrF)
      {
        halTimerSet(HAL_IDX_TIMER_APP, APP_REPORT_RETRY, HAL_TIMER_AUTO);
      }
    }
    
      appMsgRtry = APP_RETRY_CNT;  
      appFlags |= appSendingF;
    #else
        /*If ack not required*/
        sendData(ZB_BINDING_ADDR,SRCE_REPORT_ID,srceReport,4); 
        appLedBlink(APP_DATA_LED);
    #endif
    break;
  }  
}

#if APP_BLINK_LEDS
/* appLedBlink Blink the LED specified.
input parameters led - Which LED to control: Status or Data.
output parameters None.@return None. */
static void appLedBlink(uint8 led)
{
  switch (led)
  {
  case APP_STAT_LED:
    if (ZNP_NWK_CONN)
    {
      if (ZNP_NWK_COOR)
      {
        HAL_TURN_ON_RED();
        halDelay(APP_BLINK_ON_TIME, TRUE);
        HAL_TURN_OFF_RED();
      }
      else
      {
        HAL_TURN_ON_GRN();
        halDelay(APP_BLINK_ON_TIME, TRUE);
        HAL_TURN_OFF_GRN();
      }
    }
    else
    {
      HAL_TURN_ON_GRN();
      HAL_TURN_ON_RED();
      halDelay(APP_BLINK_ON_TIME, TRUE);
      HAL_TURN_OFF_GRN();
      HAL_TURN_OFF_RED();
    }
    break;

  case APP_DATA_LED:
    if (ZNP_NWK_COOR)
    {
      HAL_TURN_ON_GRN();
      halDelay(APP_BLINK_ON_TIME, TRUE);
      HAL_TURN_OFF_GRN();
    }
    else
    {
      HAL_TURN_ON_RED();
      halDelay(APP_BLINK_ON_TIME, TRUE);
      HAL_TURN_OFF_RED();
    }
    break;

  default:
    break;
  }
}
#endif
