/******************************************************************************
* ZigBeeLightTransmitter - Transmitter end device code                        *
*                                                                             *
* based on the Freescale MyApp_Ex05b demo code                                *
*                                                                             *
* Jan Hrbacek, bachelor's thesis, 2008                                        *
******************************************************************************/

#include "802_15_4.h" /* Include everything related to the 802.15.4 interface*/
#include "ToolBox.h"  /* Defines for memcpy, memcmp. */


/* PREPROCESSOR MACROS *******************************************************/

/* Defines the channels to scan. Each bit represents one channel. Use
   0x07FFF800 to scan all 16 802.15.4 channels in the 2.4GHz band. */
#define SCAN_CHANNELS 0x07FFF800

/* Maximum number of outstanding packets */
#define MAX_PENDING_DATA_PACKETS 2

/* Default size of data payload in MCPS-Data.request.
   The length has no real meaning since MCPS-Data.requests
   are always sent in one-size buffers big enough to hold
   a maximum length data frame. */
#define DEFAULT_DATA_LENGTH 3
             
/* Transmit bufer length */
#define TX_BUFFER_LEN 16

/* These constants are used for specifying the poll interval. The actual time
   in seconds is calculated as: T(x) = x*(65536/16000000) or ~ x/244 */
/* The slow polling interval is used if the coordinator
   had no data last time we polled. */
#define POLL_INTERVAL_SLOW 200 /* ~0.82 secs */
/* The fast polling interval is used if the coordinator had data last time we
   polled, thus we increase the band-width while data is available. */
#define POLL_INTERVAL_FAST 20 /* ~0.082 secs */    
          
/* Do transmit debug data over UART? */
//#define USE_UART   

#ifdef USE_UART
#include "Uart.h"     /* Defines the interface of the demo UART. */
#endif

/* LED settings */
#define LED_P       PTBD
#define LED_DD      PTBDD
#define LED_PE      PTBPE
#define LED_PIN     0x04  

#define LED_ON      LED_P &= ~LED_PIN
#define LED_OFF     LED_P |= LED_PIN
#define LED_TOGGLE  LED_P ^= LED_PIN

/* Matrix keyboard handling */
#define KBD_EN_P    PTBD
#define KBD_EN_DD   PTBDD
#define KBD_EN_PE   PTBPE
#define KBD_EN1     0x02
#define KBD_EN2     0x08

#define KBD_BTN_P   PTAD
#define KBD_BTN_DD  PTADD
#define KBD_BTN_PE  PTAPE
#define KBD_BTN1    0x01
#define KBD_BTN2    0x02
#define KBD_BTN3    0x04
#define KBD_BTN4    0x08
#define KBD_BTN5    0x10
#define KBD_BTN6    0x20

#define KBD_SET1    KBD_EN_P &= ~KBD_EN1
#define KBD_SET2    KBD_EN_P &= ~KBD_EN2
#define KBD_REL1    KBD_EN_P |= KBD_EN1
#define KBD_REL2    KBD_EN_P |= KBD_EN2

#define KBD_ENABLE  KBISC |= 0x02
#define KBD_DISABLE KBISC &= ~0x02

#define IRC_CH1     0x40
#define IRC_CH2     0x80


/* TYPE DEFINITIONS **********************************************************/
typedef struct appMessage_tag {
  uint8_t  channelId;
  uint8_t  command;
  uint8_t  data;
} appMessage_t;


/* FORWARD FUNCTION DECLARATIONS *********************************************/
void HW_init(void); // Device initialization function declaration
void Addr_init(void);
void handleInputs(void);  // input polling handler  
uint8_t getTransmitData(uint8_t *pBuffer);
void setTransmitData(appMessage_t *msg);

uint8_t App_StartScan(uint8_t scanType);
uint8_t App_HandleScanActiveConfirm(nwkMessage_t *pMsg);
uint8_t App_WaitMsg(nwkMessage_t *pMsg, uint8_t msgType);
uint8_t App_SendAssociateRequest(void);
void    App_HandleAssociateConfirm(nwkMessage_t *pMsg);
uint8_t App_HandleMlmeInput(nwkMessage_t *pMsg);
void    App_HandleMcpsInput(mcpsToNwkMessage_t *pMsgIn);
void    App_TransmitData(void);
void    App_ReceiveData(void);                          


/* VARIABLE DECLARATIONS *****************************************************/

/* All states in the applications state machine */
enum {
  stateInit,
  stateScanActiveStart,
  stateScanActiveWaitConfirm,
  stateAssociate,
  stateAssociateWaitConfirm,
  stateListen,
  stateTerminate
};

/* Error codes */
enum {
  errorNoError,
  errorWrongConfirm,
  errorNotSuccessful,
  errorNoMessage,
  errorAllocFailed,
  errorInvalidParameter,
  errorNoScanResults
};

/* The current state of the applications state machine */
uint8_t state;

/* Information about the PAN we are part of */
panDescriptor_t coordInfo;

/* This is either the short address assigned by the PAN coordinator
   during association, or our own extended MAC address. */
uint8_t myAddress[8];
/* The devices address mode. If 2, then myAddress contains the short
   address assigned by the PAN coordinator. If 3, then myAddress is
   equal to the extended address. */
uint8_t myAddrMode;    

/* Wanted PAN ID will be loaded from aExtendedAddress */
uint8_t panId[2];

/* Data request packet for sending UART input to the coordinator */
nwkToMcpsMessage_t *pPacket;

/* The MSDU handle is a unique data packet identifier */
uint8_t msduHandle;

/* Number of pending data packets */
uint8_t numPendingPackets;

/* Signals that an MLME-Poll request is pending, and that we must wait for 
   the MLME-Poll confirm message before sending the next poll request. */
bool_t waitPollConfirm;

/* Time between MLME-Poll requests */
uint8_t pollInterval;

/* Application input queues */
anchor_t mMlmeNwkInputQueue;
anchor_t mMcpsNwkInputQueue;

/* Keyboard state */
int16_t kbdState = -1; // initial state

/* IRC state */
uint8_t ircState = 0x00;

/* Transmit buffer */
appMessage_t *txBuffer[TX_BUFFER_LEN];
uint8_t txBufferHead = 0, txBufferTail = 0;

/* User-selected lightning channel ID */
uint8_t actualChannelId = 0;


/* FUNCTION DECLARATIONS *****************************************************/

/* Application Main Loop */
void main(void)
{ 
  /* Pointer for storing the messages from MLME, MCPS, and ASP. */
  void *pMsgIn;
  /* Stores the status code returned by some functions. */
  uint8_t rc;
  /* return value of Mlme_Main() - not used yet */
  uint8_t macStatus;
  
  /* Initialize variables */
  state = stateInit;

  /* Prepare input queues.*/
  MSG_InitQueue(&mMlmeNwkInputQueue);
  MSG_InitQueue(&mMcpsNwkInputQueue);

  /* Execute the application state machine */    
  while(state < stateTerminate)
  {
    /* Preset error to contain the success code */
    rc = errorNoError;
    
    /* Try to get a message from MLME */
    if (MSG_Pending(&mMlmeNwkInputQueue))
      pMsgIn = MSG_DeQueue(&mMlmeNwkInputQueue);
    else
      pMsgIn = NULL;
      
    switch(state)
    {
    case stateInit:
      /* Initialize the UART so that we can print out status messages */
#ifdef USE_UART
      Uart_Init();
#endif
      /* Initialize the 802.15.4 stack */
      Init_802_15_4();      
      /* Initialize the rest of the HW */
      HW_init();    
      /* Initialize addresses */
      Addr_init();
      
      LED_ON;
      
      /* Goto Energy Detection state. */
      state = stateScanActiveStart;
      /* Reset number of pending packets */
      numPendingPackets = 0;
      /* Allow sending a poll request */
      waitPollConfirm = FALSE;

      /* Print a welcome message to the UART */
#ifdef USE_UART
      Uart_Print("The ZigBeeLightTransmitter is initialized and ready.\n\n");
#endif
      break;
      
    case stateScanActiveStart:
      /* Start the Active scan, and goto wait for confirm state. */   
#ifdef USE_UART
      Uart_Print("Start scanning for a PAN coordinator\n"); 
#endif
      rc = App_StartScan(gScanModeActive_c);
      if (rc == errorNoError)
      {
        state = stateScanActiveWaitConfirm;
      }
      break;
      
    case stateScanActiveWaitConfirm:
      /* Stay in this state until the Scan confirm message
         arrives, and then goto the associate state. */
         
      /* ALWAYS free the beacon frame contained in the beacon notify indication.*/
      rc = App_WaitMsg(pMsgIn, gNwkBeaconNotifyInd_c);
      if (rc == errorNoError) {
        MSG_Free(((nwkMessage_t *)pMsgIn)->msgData.beaconNotifyInd.pBufferRoot);   
#ifdef USE_UART
        Uart_Print("Received an MLME-Beacon Notify Indication\n");  
#endif
      }
      
      /* Handle the Scan Confirm message. */
      rc = App_WaitMsg(pMsgIn, gNwkScanCnf_c);
      if (rc == errorNoError)
      {
        rc = App_HandleScanActiveConfirm(pMsgIn);
        if (rc == errorNoError)
        {                             
#ifdef USE_UART
          Uart_Print("Found a coordinator with the following properties:\n");
          Uart_Print("----------------------------------------------------");
          Uart_Print("\nAddress...........0x"); Uart_PrintHex(coordInfo.coordAddress, coordInfo.coordAddrMode == gAddrModeShort_c ? 2 : 8, 0);
          Uart_Print("\nPAN ID............0x"); Uart_PrintHex(coordInfo.coordPanId, 2, 0);
          Uart_Print("\nLogical Channel...0x"); Uart_PrintHex(&coordInfo.logicalChannel, 1, 0);
          Uart_Print("\nBeacon Spec.......0x"); Uart_PrintHex(coordInfo.superFrameSpec, 2, 0);
          Uart_Print("\nLink Quality......0x"); Uart_PrintHex(&coordInfo.linkQuality, 1, 0);
          Uart_Print("\n\n");         
#endif

          state = stateAssociate;
        }
        else
        {
          state = stateScanActiveStart;
#ifdef USE_UART
          Uart_Print("Scan did not find a suitable coordinator\n"); 
#endif
        }
      }
      break;

    case stateAssociate:
      /* Associate to the PAN coordinator */   
#ifdef USE_UART
      Uart_Print("Associating to PAN coordinator on channel 0x");
      Uart_PrintHex(&(coordInfo.logicalChannel), 1, gPrtHexNewLine_c); 
#endif
      rc = App_SendAssociateRequest();
      if (rc == errorNoError)
        state = stateAssociateWaitConfirm;
      break; 

    case stateAssociateWaitConfirm:
      /* Stay in this state until the Associate confirm message
         arrives, and then goto the Listen state. */
      rc = App_WaitMsg(pMsgIn, gNwkAssociateCnf_c);
      if (rc == errorNoError)
      {
        App_HandleAssociateConfirm(pMsgIn);
                       
#ifdef USE_UART
        Uart_Print("Successfully associated with the coordinator.\n");
        Uart_Print("We were assigned the short address 0x");
        Uart_PrintHex(myAddress, myAddrMode == gAddrModeShort_c ? 2 : 8, 0);
        Uart_Print("\n\nReady to send and receive data over the UART.\n\n");
#endif    

        LED_OFF;
        KBD_SET1;
        KBD_SET2;
        
        state = stateListen;
      }
      break; 
      
    case stateListen:
      /* Stay in this state forever. Handles poll confirm etc. */
      rc = App_HandleMlmeInput(pMsgIn);
      
      /* Handle the inputs */
      handleInputs();
      break;
    }
    
    if (pMsgIn)
      /* ALWAYS free messages from MLME */
      MSG_Free(pMsgIn);

    
    /* If we are associated then check MCPS queue and UART data buffer. */
    if (state == stateListen)
    {
      /* Get input from MCPS. */
      if (MSG_Pending(&mMcpsNwkInputQueue))
      {
        pMsgIn = MSG_DeQueue(&mMcpsNwkInputQueue);
        App_HandleMcpsInput(pMsgIn);
        /* ALWAYS free messages from MCPS */
        MSG_Free(pMsgIn);
      }

      /* Check if the UART buffer has data to be sent. */
      App_TransmitData();

      /* Ask coordinator if it has any data for us. */
      //App_ReceiveData();
    }
  
    /* Call the MAC main function. */
    macStatus = Mlme_Main();
  }
}    


/* Hardware initialization */
void HW_init(void)
{
  // LED
  LED_DD |= LED_PIN;
  LED_PE &= ~LED_PIN;
  LED_P  |= LED_PIN;
  
  // KBI
  /*KBISC &= ~0x02; // KBIE=0
  KBIPE = 0xFF; // all pins used
  KBISC |= 0x30; // KBIMOD=0, KBEDG4=1, KBEDG5=1
  KBISC |= 0x04; // KBACK=1*/
  KBD_BTN_DD = 0x00;
  KBD_BTN_PE = 0x00;
  KBD_EN_DD |= (KBD_EN1 | KBD_EN2);
  KBD_EN_PE &= ~(KBD_EN1 | KBD_EN2);
  KBD_EN_P  |= (KBD_EN1 | KBD_EN2);
  
  // TPM1
  // CH0 - kbd delay 50 ms
}     


/****************************************************************************** 
* The Addr_init(void) function copies part of the aExtendedAddress to the
* PAN ID
*
******************************************************************************/
void Addr_init(void)
{    
  /* This is our own extended address (MAC address). It cannot be modified. */
  extern const uint8_t aExtendedAddress[8];
  
  panId[0] = aExtendedAddress[2];
  panId[1] = aExtendedAddress[3];
}


/****************************************************************************** 
* The handleInputs(void) function handles user input on the matrix keyboard
* and scroller
*
******************************************************************************/
void handleInputs(void)
{
  uint8_t actualKbdState, diff, actualIrcState = 0, ircDir;
  appMessage_t *pMsg;
  
  if (kbdState == -1)
  {
    kbdState = PTAD;
  }
  
  if (kbdState != PTAD)
  {
    actualKbdState = PTAD;
    diff = kbdState ^ actualKbdState;
    
    if (diff & 0xC0)
    {
      // the IRC must be handled immediately
      if (actualKbdState & IRC_CH1) actualIrcState |= 0x01;
      if (actualKbdState & IRC_CH2) actualIrcState |= 0x02;
      
    	// decide the direction
    	if ((ircState == 0 && actualIrcState == 1) || (ircState == 1 && actualIrcState == 3) ||
    	    (ircState == 3 && actualIrcState == 2) || (ircState == 2 && actualIrcState == 0))
    	{
    	  ircDir = 0;
    	}
    	else
    	{
    	  ircDir = 1;
    	}
    	
    	ircState = actualIrcState;
    	
    	// compose a new command
      pMsg = MSG_AllocType(appMessage_t);
      if (pMsg != NULL)
      {
        pMsg->channelId = actualChannelId;
        pMsg->command = 0x01 + ircDir; // 0x01 - increase, 0x02 - decrease
        pMsg->data = 0x01; // 1 percent
        
      	// add the command to the queue
      	setTransmitData(pMsg);  
      }
      else
      {
        // allocation of the command buffer failed
#ifdef USE_UART
        Uart_Print("Message allocation failed!\n");     
#endif
      }
    }
    else if ((diff & 0x30) && ((actualKbdState & KBD_BTN5) || (actualKbdState & KBD_BTN6)))
    {
      // on-off buttons
      
    	// compose a new command
      pMsg = MSG_AllocType(appMessage_t);
      if (pMsg != NULL)
      {
        pMsg->channelId = actualChannelId;
        
        if (actualKbdState & KBD_BTN5)
        { 
          pMsg->command = 0x03; // 0x03 - switch on
        }
        else if (actualKbdState & KBD_BTN6)
        {
          pMsg->command = 0x04; // 0x04 - switch off
        }
        
        pMsg->data = 0x00; // no data to send
        
      	// add the command to the queue
      	setTransmitData(pMsg);  
      }
      else
      {
        // allocation of the command buffer failed
#ifdef USE_UART
        Uart_Print("Message allocation failed!\n");     
#endif
      }
    }
    else if (diff & 0x0F)
    {
      // the channel chooser can also be handled immediately
      
      // switch on the first row
      KBD_REL2;
      KBD_SET1;
      
      //if (~KBD_BTN_P & KBD_BTN1) actualChannelId = 0;
      if (~KBD_BTN_P & KBD_BTN2) actualChannelId = 0;
      if (~KBD_BTN_P & KBD_BTN3) actualChannelId = 1;
      if (~KBD_BTN_P & KBD_BTN4) actualChannelId = 2;
      
      // switch on the second row
      KBD_REL1;
      KBD_SET2;
      
      //if (~KBD_BTN_P & KBD_BTN1) actualChannelId = 4;
      if (~KBD_BTN_P & KBD_BTN2) actualChannelId = 3;
      if (~KBD_BTN_P & KBD_BTN3) actualChannelId = 4;
      if (~KBD_BTN_P & KBD_BTN4) actualChannelId = 5;
      
      // switch on both rows
      KBD_SET1;
      KBD_SET2;
    }
  
    kbdState = actualKbdState;
  }
}


/****************************************************************************** 
* The KBI_ISR(void) interrupt routine handles user input on the matrix keybd
*
******************************************************************************/
/*interrupt void KBI_ISR(void)
{
  uint8_t values = PTAD;

  LED_ON;
                          
  // clear KBF
  KBISC |= 0x04;
}*/             


/******************************************************************************
* The App_StartScan(scanType) function will start the scan process of the
* specified type in the MAC. This is accomplished by allocating a MAC message,
* which is then assigned the desired scan parameters and sent to the MLME
* service access point.
* The function may return either of the following values:
*   errorNoError:          The Scan message was sent successfully.
*   errorInvalidParameter: The MLME service access point rejected the
*                          message due to an invalid parameter.
*   errorAllocFailed:      A message buffer could not be allocated.
*
******************************************************************************/
uint8_t App_StartScan(uint8_t scanType)
{
  mlmeMessage_t *pMsg;
  mlmeScanReq_t *pScanReq;
          
#ifdef USE_UART
  Uart_Print("Sending the MLME-Scan Request message to the MAC..."); 
#endif

  /* Allocate a message for the MLME (We should check for NULL). */
  pMsg = MSG_AllocType(mlmeMessage_t);
  if (pMsg != NULL)
  {
    /* This is a MLME-START.req command */
    pMsg->msgType = gMlmeScanReq_c;
    /* Create the Start request message data. */
    pScanReq = &pMsg->msgData.scanReq;
    /* gScanModeED_c, gScanModeActive_c, gScanModePassive_c, or gScanModeOrphan_c */
    pScanReq->scanType = scanType;
    /* ChannelsToScan & 0xFF - LSB, always 0x00 */
    pScanReq->scanChannels[0] = (uint8_t)((SCAN_CHANNELS)     & 0xFF);
    /* ChannelsToScan>>8 & 0xFF  */
    pScanReq->scanChannels[1] = (uint8_t)((SCAN_CHANNELS>>8)  & 0xFF);
    /* ChannelsToScan>>16 & 0xFF  */
    pScanReq->scanChannels[2] = (uint8_t)((SCAN_CHANNELS>>16) & 0xFF);
    /* ChannelsToScan>>24 & 0xFF - MSB */
    pScanReq->scanChannels[3] = (uint8_t)((SCAN_CHANNELS>>24) & 0xFF);
    /* Duration per channel 0-14 (dc). T[sec] = (16*960*((2^dc)+1))/1000000.
       A scan duration of 5 on 16 channels approximately takes 8 secs. */
    pScanReq->scanDuration = 5;
    
    /* Send the Scan request to the MLME. */
    if (MSG_Send(NWK_MLME, pMsg) == gSuccess_c)
    {       
#ifdef USE_UART
      Uart_Print("Done\n");  
#endif
      return errorNoError;
    }
    else
    {      
#ifdef USE_UART
      Uart_Print("Invalid parameter!\n"); 
#endif
      return errorInvalidParameter;
    }
  }
  else
  {
    /* Allocation of a message buffer failed. */  
#ifdef USE_UART
    Uart_Print("Message allocation failed!\n"); 
#endif
    return errorAllocFailed;
  }
}

/******************************************************************************
* The App_HandleScanActiveConfirm(nwkMessage_t *pMsg) function will handle the
* Active Scan confirm message received from the MLME when the Active scan has
* completed. The message contains a list of PAN descriptors. Based on link
* quality inforamtion in the pan descriptors the nearest coordinator is chosen.
* The corresponding pan descriptor is stored in the global variable coordInfo. 
*
* The function may return either of the following values:
*   errorNoError:       A suitable pan descriptor was found.
*   errorNoScanResults: No scan results were present in the confirm message.
*
******************************************************************************/
uint8_t App_HandleScanActiveConfirm(nwkMessage_t *pMsg)
{
  uint8_t panDescListSize   = pMsg->msgData.scanCnf.resultListSize;
  panDescriptor_t *pPanDesc = pMsg->msgData.scanCnf.resList.pPanDescriptorList;
  uint8_t rc = errorNoScanResults;
 
  /* Check if the scan resulted in any coordinator responses. */
  if (panDescListSize != 0)
  {
    /* Initialize link quality to very poor. */
    uint8_t i, bestLinkQuality = 0;
    
    /* Check all PAN descriptors. */
    for(i=0; i<panDescListSize; i++, pPanDesc++)
    {
      /* Only attempt to associate if the coordinator
         accepts associations and is non-beacon. */
      if ((pPanDesc->superFrameSpec[1] & gSuperFrameSpecMsbAssocPermit_c) && 
          ((pPanDesc->superFrameSpec[0] & gSuperFrameSpecLsbBO_c) == 0x0F))
      {
        /* Find the nearest coordinator using the link quality measure. */
        if (pPanDesc->coordPanId[0] == panId[0] && pPanDesc->coordPanId[1] == panId[1] &&
           pPanDesc->linkQuality > bestLinkQuality)
        {
          /* Save the information of the coordinator candidate. If we
             find a better candiate, the information will be replaced. */
          memcpy(&coordInfo, pPanDesc, sizeof(panDescriptor_t));
          bestLinkQuality = pPanDesc->linkQuality;
          rc = errorNoError;
        }
      }
    }
  }
  /* ALWAYS free the PAN descriptor list */
  MSG_Free(pMsg->msgData.scanCnf.resList.pPanDescriptorList);
  
  return rc;
}


/******************************************************************************
* The App_SendAssociateRequest(void) will create an Associate Request message
* and send it to the coordinator it wishes to associate to. The function uses
* information gained about the coordinator during the scan procedure.
*
* The function may return either of the following values:
*   errorNoError:          The Associate Request message was sent successfully.
*   errorInvalidParameter: The MLME service access point rejected the
*                          message due to an invalid parameter.
*   errorAllocFailed:      A message buffer could not be allocated.
*
******************************************************************************/
uint8_t App_SendAssociateRequest(void)
{
  mlmeMessage_t *pMsg;
  mlmeAssociateReq_t *pAssocReq;
         
#ifdef USE_UART
  Uart_Print("Sending the MLME-Associate Request message to the MAC...");
#endif
  
  /* Allocate a message for the MLME message. */
  pMsg = MSG_AllocType(mlmeMessage_t);
  if (pMsg != NULL)
  {
    /* This is a MLME-ASSOCIATE.req command. */
    pMsg->msgType = gMlmeAssociateReq_c;
    
    /* Create the Associate request message data. */
    pAssocReq = &pMsg->msgData.associateReq;
 
    /* Use the coordinator info we got from the Active Scan. */
    memcpy(pAssocReq->coordAddress, coordInfo.coordAddress, 8);
    memcpy(pAssocReq->coordPanId,   coordInfo.coordPanId, 2);
    pAssocReq->coordAddrMode      = coordInfo.coordAddrMode;
    pAssocReq->logicalChannel     = coordInfo.logicalChannel;
    pAssocReq->securityEnable     = FALSE;
    /* We want the coordinator to assign a short address to us. */
    pAssocReq->capabilityInfo     = gCapInfoAllocAddr_c;
      
    /* Send the Associate Request to the MLME. */
    if (MSG_Send(NWK_MLME, pMsg) == gSuccess_c)
    {                 
#ifdef USE_UART
      Uart_Print("Done\n");   
#endif
      return errorNoError;
    }
    else
    {
      /* One or more parameters in the message were invalid. */  
#ifdef USE_UART
      Uart_Print("Invalid parameter!\n");
#endif
      return errorInvalidParameter;
    }
  }
  else
  {
    /* Allocation of a message buffer failed. */ 
#ifdef USE_UART
    Uart_Print("Message allocation failed!\n");     
#endif
    return errorAllocFailed;
  }
}

/******************************************************************************
* The App_HandleAssociateConfirm(nwkMessage_t *pMsg) function will handle the
* Associate confirm message received from the MLME when the Association
* procedure has completed. The message contains the short address that the
* coordinator has assigned to us. This address is 0xfffe if we did not specify
* the gCapInfoAllocAddr_c flag in the capability info field of the Associate
* request. The address and address mode are saved in global variables. They
* will be used in the next demo application when sending data.
*
******************************************************************************/
void App_HandleAssociateConfirm(nwkMessage_t *pMsg)
{
  /* This is our own extended address (MAC address). It cannot be modified. */
  extern const uint8_t aExtendedAddress[8];
  
  /* If the coordinator assigns a short address of 0xfffe then,
     that means we must use our own extended address in all
     communications with the coordinator. Otherwise, we use
     the short address assigned to us. */
  if ((pMsg->msgData.associateCnf.assocShortAddress[0] >= 0xFE) && 
      (pMsg->msgData.associateCnf.assocShortAddress[1] == 0xFF))
  {
    myAddrMode = gAddrModeLong_c;
    memcpy(myAddress, (void *) aExtendedAddress, 8);
  }
  else
  {
    myAddrMode = gAddrModeShort_c;
    memcpy(myAddress, pMsg->msgData.associateCnf.assocShortAddress, 2);
  }
}


/******************************************************************************
* The App_HandleMlmeInput(nwkMessage_t *pMsg) function will handle various
* messages from the MLME, e.g. poll confirm.
*
* The function may return either of the following values:
*   errorNoError:   The message was processed.
*   errorNoMessage: The message pointer is NULL.
******************************************************************************/
uint8_t App_HandleMlmeInput(nwkMessage_t *pMsg)
{
  uint8_t ret = errorNoError;
  
  if (pMsg == NULL)
    return errorNoMessage;
  
  LED_ON;
  
  /* Handle the incoming message. The type determines the sort of processing.*/
  switch(pMsg->msgType) {
  case gNwkPollCnf_c:
    if (pMsg->msgData.pollCnf.status != gSuccess_c)
    {
      /* The Poll Confirm status was not successful. Usually this happens if
         no data was available at the coordinator. In this case we start
         polling at a lower rate to conserve power. */
      pollInterval = POLL_INTERVAL_SLOW;
      
      /* If we get to this point, then no data was available, and we
         allow a new poll request. Otherwise, we wait for the data
         indication before allowing the next poll request. */
      waitPollConfirm = FALSE;
    }
    
    break;
  }
  
  LED_OFF;
  
  return ret;
}

/******************************************************************************
* The App_HandleMcpsInput(mcpsToNwkMessage_t *pMsgIn) function will handle 
* messages from the MCPS, e.g. Data Confirm, and Data Indication.
*
******************************************************************************/
void App_HandleMcpsInput(mcpsToNwkMessage_t *pMsgIn)
{
  LED_ON;

  switch(pMsgIn->msgType)
  {
    /* The MCPS-Data confirm is sent by the MAC to the network 
       or application layer when data has been sent. */
  case gMcpsDataCnf_c:
    if (numPendingPackets)
      numPendingPackets--;
    break;

  case gMcpsDataInd_c:
    /* Copy the received data to the UART. */
    //Uart_Tx(pMsgIn->msgData.dataInd.msdu, pMsgIn->msgData.dataInd.msduLength);
    /* Since we received data, the coordinator might have more to send. We 
       reduce the polling interval to raise the throughput while data is
       available. */
    pollInterval = POLL_INTERVAL_FAST;
    /* Allow another MLME-Poll request. */
    waitPollConfirm = FALSE;
    break;
  }
  
  LED_OFF;
}

/******************************************************************************
* The App_WaitMsg(nwkMessage_t *pMsg, uint8_t msgType) function does not, as
* the name implies, wait for a message, thus blocking the execution of the
* state machine. Instead the function analyzes the supplied message to 
* determine whether or not the message is of the expected type.
* The function may return either of the following values:
*   errorNoError: The message was of the expected type.
*   errorNoMessage: The message pointer is NULL.
*   errorWrongConfirm: The message is not of the expected type.
*
******************************************************************************/
uint8_t App_WaitMsg(nwkMessage_t *pMsg, uint8_t msgType)
{
  /* Do we have a message? If not, the exit with error code */
  if (pMsg == NULL)
    return errorNoMessage;

  /* Is it the expected message type? If not then exit with error code */
  if (pMsg->msgType != msgType)
    return errorWrongConfirm;

  /* Found the expected message. Return with success code */
  return errorNoError;
}

/******************************************************************************
* The App_TransmitData() function will perform (single/multi buffered)
* data transmissions of data received by the UART. Data could also come from
* other sources such as sensors etc. This is completely determined by the
* application. The constant MAX_PENDING_DATA_PACKETS determine the maximum
* number of packets pending for transmission in the MAC. A global variable
* is incremented each time a data packet is sent to the MCPS, and decremented
* when the corresponding MCPS-Data Confirm message is received. If the counter
* reaches the defined maximum no more data buffers are allocated until the
* counter is decreased below the maximum number of pending packets.
*
* The function uses the coordinator information gained during the Active Scan,
* and the short address assigned to us by coordinator, for building an MCPS-
* Data Request message. The message is sent to the MCPS service access point
* in the MAC.
******************************************************************************/
void App_TransmitData(void)
{   
  if ((numPendingPackets < MAX_PENDING_DATA_PACKETS) && (pPacket == NULL))
  {
    /* If the maximum number of pending data buffes is below maximum limit 
       and we do not have a data buffer already then allocate one. */
    pPacket = MSG_Alloc(sizeof(nwkToMcpsMessage_t) - 1 + DEFAULT_DATA_LENGTH);
  }

  if (pPacket != NULL)
  {
    /* If we have a buffer, then get data from the transmit ring buffer. */
    uint8_t msduLength = getTransmitData(pPacket->msgData.dataReq.msdu);
    if (msduLength)
    {
      LED_ON;
      
      /* Data was available in the UART receive buffer. Now create an
         MCPS-Data Request message containing the UART data. */
      pPacket->msgType = gMcpsDataReq_c;
      /* Create the header using coordinator information gained during 
         the scan procedure. Also use the short address we were assigned
         by the coordinator during association. */
      memcpy(pPacket->msgData.dataReq.dstAddr, coordInfo.coordAddress, 8);
      memcpy(pPacket->msgData.dataReq.srcAddr, myAddress, 8);
      memcpy(pPacket->msgData.dataReq.dstPanId, coordInfo.coordPanId, 2);
      memcpy(pPacket->msgData.dataReq.srcPanId, coordInfo.coordPanId, 2);
      pPacket->msgData.dataReq.dstAddrMode = coordInfo.coordAddrMode;
      pPacket->msgData.dataReq.srcAddrMode = myAddrMode;
      pPacket->msgData.dataReq.msduLength = msduLength;
      /* Request MAC level acknowledgement of the data packet */
      pPacket->msgData.dataReq.txOptions = gTxOptsAck_c;
      /* Give the data packet a handle. The handle is
         returned in the MCPS-Data Confirm message. */
      pPacket->msgData.dataReq.msduHandle = msduHandle++;
      
      /* Send the Data Request to the MCPS */
      NR MSG_Send(NWK_MCPS, pPacket);
      /* Prepare for another data buffer */
      pPacket = NULL;
      numPendingPackets++;
      
      LED_OFF;
    }
  }
}


/* Helper funcs, inspired by Uart lib */
uint8_t getTransmitData(uint8_t *pBuffer)
{
  appMessage_t *pMsg;
  
  if (txBufferHead == txBufferTail)
  {
    return 0; // no messages in buffer, exit
  }
    
	pMsg = txBuffer[txBufferTail];	// read the data, increment the pointer
  txBufferTail = (txBufferTail + 1) & (TX_BUFFER_LEN - 1);

  // copy the message to the buffer
  *(pBuffer++) = pMsg->channelId;
  *(pBuffer++) = pMsg->command;
  *(pBuffer++) = pMsg->data;
  
  MSG_Free(pMsg);
  pMsg = NULL;

  return 3; // True indicates new data ready
}

     
void setTransmitData(appMessage_t *pMsg)
{
	txBuffer[txBufferHead] = pMsg;
  txBufferHead = (txBufferHead + 1) & (TX_BUFFER_LEN - 1);
}


/******************************************************************************
* The App_ReceiveData() function will check if it is time to send out an
* MLME-Poll request in order to receive data from the coordinator. If its time,
* and we are permitted then a poll request is created and sent.
* 
* The function uses the coordinator information gained during the Active Scan
* for building the MLME-Poll Request message. The message is sent to the MLME
* service access point in the MAC.
******************************************************************************/
void App_ReceiveData(void)
{ 
  /* Check if we are permitted, and if it is time to send a poll request.
     The poll interval is adjusted dynamically to the current band-width
     requirements. */
  if ((waitPollConfirm == FALSE))// && (Timer_Get() > pollInterval))
  {
    /* This is an MLME-POLL.req command. */
    mlmeMessage_t *pMlmeMsg = MSG_AllocType(mlmeMessage_t);
    if (pMlmeMsg)
    {
      /* Create the Poll Request message data. */
      pMlmeMsg->msgType = gMlmePollReq_c;
 
      /* Use the coordinator information we got from the Active Scan. */
      memcpy(pMlmeMsg->msgData.pollReq.coordAddress, coordInfo.coordAddress, 8);
      memcpy(pMlmeMsg->msgData.pollReq.coordPanId, coordInfo.coordPanId, 2);
      pMlmeMsg->msgData.pollReq.coordAddrMode = coordInfo.coordAddrMode;
      pMlmeMsg->msgData.pollReq.securityEnable = FALSE;
      
      /* Send the Poll Request to the MLME. */
      if (MSG_Send(NWK_MLME, pMlmeMsg) == gSuccess_c)
      {
        /* Do not allow another Poll request before the confirm is received. */
        waitPollConfirm = TRUE;
        /* Restart timer. */
        //Timer_Reset();
      }
    }
  }
}

/******************************************************************************
* The following functions are called by the MAC to put messages into the
* Application's queue. They need to be defined even if they are not used
* in order to avoid linker errors.
******************************************************************************/

uint8_t MLME_NWK_SapHandler(nwkMessage_t *pMsg)
{
  /* Put the incoming MLME message in the applications input queue. */
  MSG_Queue(&mMlmeNwkInputQueue, pMsg);
  return gSuccess_c;
}

uint8_t MCPS_NWK_SapHandler(mcpsToNwkMessage_t *pMsg)
{
  /* Put the incoming MCPS message in the applications input queue. */
  MSG_Queue(&mMcpsNwkInputQueue, pMsg);
  return gSuccess_c;
}

uint8_t ASP_APP_SapHandler(aspToAppMsg_t *pMsg)
{
  /* If the message is not handled anywhere it must be freed. */
  MSG_Free(pMsg);
  return gSuccess_c;
}