/**
  @file  msa.c
  @brief TI RTOS sample application interfacing with TIMAC stack.

  The application interacts with TIMAC stack
  via both messaging interface and C function interface.

  <!--
  Copyright 2013-2015 Texas Instruments Incorporated. All rights reserved.

  IMPORTANT: Your use of this Software is limited to those specific rights
  granted under the terms of a software license agreement between the user
  who downloaded the software, his/her employer (which must be your employer)
  and Texas Instruments Incorporated (the "License").  You may not use this
  Software unless you agree to abide by the terms of the License. The License
  limits your use, and you acknowledge, that the Software may not be modified,
  copied or distributed unless embedded on a Texas Instruments microcontroller
  or used solely and exclusively in conjunction with a Texas Instruments radio
  frequency transceiver, which is integrated into your product.  Other than for
  the foregoing purpose, you may not use, reproduce, copy, prepare derivative
  works of, modify, distribute, perform, display or sell this Software and/or
  its documentation for any purpose.

  YOU FURTHER 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.

  Should you have any questions regarding your right to use this Software,
  contact Texas Instruments Incorporated at www.TI.com.
  -->
*/

/**************************************************************************************************

    Description:

                                KEY UP 
                              - Non Beacon
                              - Sets up device flashed with FFD image as PAN coordinator. 
                              - Sets up device flashed with RFD image as end-device.
                                 |
          KEY LEFT               |      KEY RIGHT (or KEY SELECT)
                             ----+----- - Start transmitting
                                 |
                                 |
                                KEY DOWN



**************************************************************************************************/


/**************************************************************************************************
 *                                           Includes
 **************************************************************************************************/

#include <xdc/std.h>

#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>

#include <ti/sysbios/BIOS.h>

#include <ti/sysbios/knl/Clock.h>
#include <ti/sysbios/family/arm/m3/Hwi.h>
#include <ti/sysbios/knl/Semaphore.h>
#include <ti/sysbios/family/arm/cc26xx/Power.h>
#include <ti/drivers/PIN.h>
#include <string.h>
#include <inc/hw_ints.h>
#include "ICall.h"

#include "Macs.h"
#include "MacStackMSG.h"

#include <aon_event.h>
#include <ioc.h>

#include "Board.h"
#include "msa.h"

#ifdef NV_RESTORE
#include "nv_wrapper.h"
#include "MacComdef.h"
#include "mac_nv.h"
#define MAX_DEVICE_TABLE_ENTRIES   8
#endif
/**************************************************************************************************
 *                                           Constant
 **************************************************************************************************/

#define TIMAC_ABORT() ICall_abort()

#define HI_UINT16(a) (((a) >> 8) & 0xFF)
#define LO_UINT16(a) ((a) & 0xFF)

/** Device initial short address - This will change after association */
#define MSA_DEV_SHORT_ADDR        0x0000
/** Header includes DataLength + DeviceShortAddr + Sequence */
#define MSA_HEADER_LENGTH         4  
/** Echo packet */
#define MSA_ECHO_LENGTH           8             
/** Maximun number of scan result that will be accepted */
#define MSA_MAC_MAX_RESULTS       5 
/** Maximun number of devices can associate with the coordinator */
#define MSA_MAX_DEVICE_NUM        50            
#define MSA_EBR_PERMITJOINING     TRUE
#define MSA_EBR_LINKQUALITY       1
#define MSA_EBR_PERCENTFILTER     0xFF
#define MSA_LED4_WAIT_PERIOD      500
#define MSA_LED4_INITIAL_PERIOD   100

/* Debounce timeout in ticks */
#define KEY_DEBOUNCE_TIMEOUT                  100

/**************************************************************************************************
 *                                        GLOBAL VARIABLES
 **************************************************************************************************/

/* Semaphore globally used to post events to the application thread */
ICall_Semaphore sem;
ICall_EntityID macAppEntity;

/* Task pending events */
static uint16_t msa_events = 0;

/** Contains pan descriptor results from scan */
Timac_MacPanDesc_t  msa_PanDesc[MSA_MAC_MAX_RESULTS];

 
/**
 * Extended address of the device, for coordinator, it will be msa_ExtAddr1
 * For any device, it will be msa_ExtAddr2 with the last 2 bytes from a ADC read
 */
Timac_sAddrExt_t msa_ExtAddr;
Timac_sAddrExt_t msa_ExtAddr1 = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
Timac_sAddrExt_t msa_ExtAddr2 = {0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0x00, 0x00};

/** Coordinator and Device information */
uint_least16_t msa_PanId = MSA_PAN_ID;
uint_least16_t msa_CoordShortAddr = MSA_COORD_SHORT_ADDR;
uint_least16_t msa_DevShortAddr   = MSA_DEV_SHORT_ADDR;

/**
 * List of short addresses that the coordinator will use
 * to assign to each the device that associates to it
 */
uint_least16_t msa_DevShortAddrList[] = {0x0001, 0x0002, 0x0003, 0x0004, 0x0005,
                                         0x0006, 0x0007, 0x0008, 0x0009, 0x000A,
                                         0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
                                         0x0010, 0x0011, 0x0012, 0x0013, 0x0014,
                                         0x0015, 0x0016, 0x0017, 0x0018, 0x0019,
                                         0x001A, 0x001B, 0x001C, 0x001D, 0x001E,
                                         0x001F, 0x0020, 0x0021, 0x0022, 0x0023,
                                         0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
                                         0x0029, 0x002A, 0x002B, 0x002C, 0x002D,
                                         0x002E, 0x002F, 0x0030, 0x0031, 0x0032};

/** Current number of devices associated to the coordinator */
uint_least8_t msa_NumOfDevices = 0;

bool msa_IsScanRequest = FALSE;

#ifdef FEATURE_MAC_SECURITY
  /** Current number of devices (including coordinator) communicating to this device */
  uint_least8_t msa_NumOfSecuredDevices = 0;
#endif /* FEATURE_MAC_SECURITY */

/** Predefined packet that will be sent out by the coordinator */
uint_least8_t msa_Data1[MSA_PACKET_LENGTH];

/** Predefined packet that will be sent back to the coordinator by the device */
uint_least8_t msa_Data2[MSA_ECHO_LENGTH];

/** TRUE and FALSE value */
bool msa_MACTrue = TRUE;
bool msa_MACFalse = FALSE;

/** Beacon payload, this is used to determine if the device is not zigbee device */
uint_least8_t msa_BeaconPayload[] = {0x22, 0x33, 0x44};
uint_least8_t msa_BeaconPayloadLen = 3;

/** Contains pan descriptor results from scan */
Timac_MacPanDesc_t  msa_PanDesc[MSA_MAC_MAX_RESULTS];

/** flags used in the application */
/** True if the device is started as a Pan Coordinate */
bool          msa_IsCoordinator  = FALSE;  
/** True if the device started, either as Pan Coordinator or device */
bool          msa_IsStarted      = FALSE; 
/** True if the beacon payload match with the predefined */
bool          msa_IsSampleBeacon = FALSE; 
/** True if the messages will be sent as direct messages */
bool          msa_IsDirectMsg    = FALSE;  
/** Either IDLE state or SEND state */
uint_least8_t msa_State = MSA_IDLE_STATE;

/* Structure that used for association request */
Timac_MacMlmeAssociateReq_t msa_AssociateReq;

/* Structure that used for association response */
Timac_MacMlmeAssociateRsp_t msa_AssociateRsp;

/* Structure that contains information about the device that associates with the coordinator */
typedef struct
{
  uint_least16_t devShortAddr;
  uint_least8_t  isDirectMsg;
}msa_DeviceInfo_t;

/* Array contains the information of the devices */
static msa_DeviceInfo_t msa_DeviceRecord[MSA_MAX_DEVICE_NUM];

uint_least8_t msa_SuperFrameOrder;
uint_least8_t msa_BeaconOrder;

/* Clock resorces */
static Clock_Params msaSendParams, msaPollParams, msaLed4Params, msaKeyParams;
static Clock_Struct msaSend, msaPoll, msaLed4, msaKey;

static void MSA_ClockFxn(UArg param);

/** LED globals */

/* MSA LED has exactly the same attributes as that of BoardGpioInitTable[].
 * There is no need to create a new one. 
 */
static PIN_Config ledPinTable[] = {
#if defined (MODULE_CC26XX_7X7)
  Board_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED1 initially off */
  Board_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED2 initially off */
#elif defined (MODULE_CC26XX_5X5)
  /* Board_LED1 and Board_LED2 are not connected to MODULE_CC26XX_5X5. */
#elif defined (MODULE_CC26XX_4X4)
  /* Board_LED1 and Board_LED2 are not connected to MODULE_CC26XX_4X4. */
#elif
  #error "Must define either 'MODULE_CC26XX_7X7', 'MODULE_CC26XX_5X5', or 'MODULE_CC26XX_4X4'."
#endif /* MODULE_CC26XX_7X7 */
  Board_LED3 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED3 initially off */
  Board_LED4 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED4 initially off */
  PIN_TERMINATE                                                                   /* Terminate list     */
};

/* LED pin state */
static PIN_State ledPinState;

/* LED Pin Handle */
PIN_Handle ledPinHandle;

/** KEY globals */

/* Create the MSA KEY pin table. This will override the key attributes in 
 * BoardGpioInitTable[]. 
 */
static PIN_Config keyPinTable[] = {
  Board_KEY_SELECT | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE, /* KEY SELECT     */
  Board_KEY_UP     | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE, /* KEY UP         */
  Board_KEY_DOWN   | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE, /* KEY DOWN       */
#if defined (MODULE_CC26XX_7X7)
  Board_KEY_LEFT   | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE, /* KEY LEFT       */
  Board_KEY_RIGHT  | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE, /* KEY RIGHT      */
#elif defined (MODULE_CC26XX_5X5)
  Board_KEY_LEFT   | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE, /* KEY LEFT       */
#ifndef PA_LNA_CC2592
  /* Board_KEY_RIGHT is using IOID_13 which is also used by CC2592 */
  Board_KEY_RIGHT  | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE, /* KEY RIGHT      */
#endif /* PA_LNA_CC2592 */
#elif defined (MODULE_CC26XX_4X4)
  /* Board_KEY_LEFT and Board_KEY_RIGHT are not connected to MODULE_CC26XX_4X4. */
#elif
  #error "Must define either 'MODULE_CC26XX_7X7', 'MODULE_CC26XX_5X5', or 'MODULE_CC26XX_4X4'."
#endif /* MODULE_CC26XX_7X7 */ 
  PIN_TERMINATE                                                   /* Terminate list */
};

/* KEY pin state */
static PIN_State keyPinState;

/* KEY Pin Handle */
PIN_Handle keyPinHandle;

/* Keypress callbacks */
static void keyFxn(PIN_Handle keyPinHandle, PIN_Id keyPinId);

/* Key press parameters */
static uint8_t keys;

/* Initialize keys */
static void MSA_initKeys(void);

/* Key press callback */
void MSA_keyCB(UArg a0);

/* Handle keys */
static void MSA_HandleKeys(uint8_t keys);

/* Handles NV Restore Event */
#ifdef NV_RESTORE
void MSA_NvRestore(void);
static void MSA_NvReset(void);
static uint8 srcMatchisEnabled = 0;
#endif

#ifdef FEATURE_MAC_SECURITY
/**************************************************************************************************
 *                                  MAC security related constants
 **************************************************************************************************/
#define MSA_KEY_TABLE_ENTRIES         1
#define MSA_KEY_ID_LOOKUP_ENTRIES     1
#define MSA_KEY_DEVICE_TABLE_ENTRIES  8
#define MSA_KEY_USAGE_TABLE_ENTRIES   1
#define MSA_DEVICE_TABLE_ENTRIES      0 /* can grow up to MAX_DEVICE_TABLE_ENTRIES */
#define MSA_SECURITY_LEVEL_ENTRIES    1
#define MSA_MAC_SEC_LEVEL             MAC_SEC_LEVEL_ENC_MIC_32
#define MSA_MAC_KEY_ID_MODE           MAC_KEY_ID_MODE_1
#define MSA_MAC_KEY_SOURCE            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
#define MSA_MAC_DEFAULT_KEY_SOURCE    {0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33}
#define MSA_MAC_KEY_INDEX             3  /* cannot be zero for implicit key identifier */


#define MAC_FRAME_TYPE_DATA             1
#define MAC_DATA_REQ_FRAME              4


/* Default MSA Security Parameters for outgoing frames */
bool  macSecurity       = TRUE;
uint_least8_t msa_securityLevel = MSA_MAC_SEC_LEVEL;
uint_least8_t msa_keyIdMode     = MSA_MAC_KEY_ID_MODE;
uint_least8_t msa_keySource[]   = MSA_MAC_KEY_SOURCE;
uint_least8_t msa_keyIndex      = MSA_MAC_KEY_INDEX;


/**************************************************************************************************
 *                                 Security PIBs for outgoing frames
 **************************************************************************************************/
const keyIdLookupDescriptor_t msa_keyIdLookupList[] =
{
  {
    {0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x03}, 0x01 /* index 3, 9 octets */
  }
};

/* Key device list can be modified at run time
 */
keyDeviceDescriptor_t msa_keyDeviceList[] =
{
  {0x00, false, false},
  {0x00, false, false},
  {0x00, false, false},
  {0x00, false, false},
  {0x00, false, false},
  {0x00, false, false},
  {0x00, false, false},
  {0x00, false, false}
};

const keyUsageDescriptor_t msa_keyUsageList[] =
{
  {MAC_FRAME_TYPE_DATA, MAC_DATA_REQ_FRAME}
};

keyDescriptor_t msa_keyTable[] =
{
  {
    (keyIdLookupDescriptor_t *)msa_keyIdLookupList, MSA_KEY_ID_LOOKUP_ENTRIES,
    (keyDeviceDescriptor_t *)msa_keyDeviceList, MSA_KEY_DEVICE_TABLE_ENTRIES,
    (keyUsageDescriptor_t *)msa_keyUsageList, MSA_KEY_USAGE_TABLE_ENTRIES,
    {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0}
  
  }
};

const uint_least8_t msa_keyDefaultSource[] = MSA_MAC_DEFAULT_KEY_SOURCE;


/**************************************************************************************************
 *                                 Security PIBs for incoming frames
 **************************************************************************************************/

/* Device table can be modified at run time. */
deviceDescriptor_t msa_deviceTable[] =
{
  {0, 0xFFFF, 0, 0, FALSE},
  {0, 0xFFFF, 0, 0, FALSE},
  {0, 0xFFFF, 0, 0, FALSE},
  {0, 0xFFFF, 0, 0, FALSE},
  {0, 0xFFFF, 0, 0, FALSE},
  {0, 0xFFFF, 0, 0, FALSE},
  {0, 0xFFFF, 0, 0, FALSE},
  {0, 0xFFFF, 0, 0, FALSE}
};

const securityLevelDescriptor_t msa_securityLevelTable[] =
{
  {MAC_FRAME_TYPE_DATA, MAC_DATA_REQ_FRAME, MAC_SEC_LEVEL_NONE, FALSE}
};

void MSA_SecurityInit(void);
void MSA_SecuredDeviceTableUpdate(uint_least16_t panID,
                                  uint_least16_t shortAddr,
                                  Timac_sAddrExt_t extAddr,
                                  uint_least8_t *pNumOfSecuredDevices);
#else /* FEATURE_MAC_SECURITY */
uint_least8_t msa_securityLevel = MAC_SEC_LEVEL_NONE;
uint_least8_t msa_keyIdMode     = MAC_KEY_ID_MODE_NONE;
uint_least8_t msa_keySource[]   = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint_least8_t msa_keyIndex      = 0;
#endif /* FEATURE_MAC_SECURITY */

/** Support */
bool MSA_BeaconPayLoadCheck(uint8* pSdu);
bool MSA_DataCheck(uint8* data, uint8 dataLength);


/**
 * @internal A semaphore used to wait on a clock event
 */
extern ti_sysbios_knl_Semaphore_Handle semaphore0;

/**
 * @internal Clock handler function
 * @param a0 ignored
 */
Void tirtosapp_clock(UArg a0)
{
  /* Wake up the application thread when it waits for clock event */
  Semaphore_post(semaphore0);
}

  Timac_MacMlmeScanReq_t scanReq;
 uint8 msa_energyDetect[100];
 
uint_least8_t ED_result[18]; //

/**************************************************************************************************
 *
 * @fn      MSA_ScanReq()
 *
 * @brief   Performs active scan on specified channel
 *
 * @param   None
 *
 * @return  None
 *
 **************************************************************************************************/
void MSA_ScanReq(uint_least8_t  scanType, uint_least8_t  scanDuration)
{
//  Timac_MacMlmeScanReq_t scanReq;

  /* Fill in information for scan request structure */
  //moto START
  //Orig

    scanReq.scanChannels = (uint32) 1 << MSA_MAC_CHANNEL;
    scanReq.scanType = MAC_SCAN_ED;
    scanReq.scanDuration = 3;
    scanReq.channelPage = MAC_CHANNEL_PAGE_0;
    scanReq.maxResults = 5;
    scanReq.permitJoining = TRUE;
    scanReq.linkQuality = 1;
    scanReq.percentFilter = 0xFF;
    scanReq.result.pPanDescriptor = msa_PanDesc;
    scanReq.result.pEnergyDetect = ED_result;
    memset(&scanReq.sec, 0, sizeof(Timac_MacSec_t));
    
  /* Call scan request */
  MAC_MlmeScanReqMsg(&scanReq);
}


/**************************************************************************************************
 *
 * @fn      MSA_SyncReq()
 *
 * @brief   Sync Request
 *
 * @param   None
 *
 * @return  None
 *
 **************************************************************************************************/
void MSA_SyncReq(void)
{
  Timac_MacMlmeSyncReq_t  syncReq;

  /* Fill in information for sync request structure */
  syncReq.logicalChannel = MSA_MAC_CHANNEL;
  syncReq.channelPage    = MAC_CHANNEL_PAGE_0;
  syncReq.trackBeacon    = TRUE;

  /* Call sync request */
  MAC_MlmeSyncReqMsg(&syncReq);
}


/**************************************************************************************************
 * @fn          MAC_CbackQueryRetransmit
 *
 * @brief       This function callback function returns whether or not to continue MAC
 *              retransmission.
 *              A return value '0x00' will indicate no continuation of retry and a return value
 *              '0x01' will indicate to continue retransmission. This callback function shall be
 *              used to stop continuing retransmission for RF4CE.
 *              MAC shall call this callback function whenever it finishes transmitting a packet
 *              for macMaxFrameRetries times.
 *
 * input parameters
 *
 * None.
 *
 * output parameters
 *
 * None.
 *
 * @return      0x00 to stop retransmission, 0x01 to continue retransmission.
 **************************************************************************************************
*/
uint8 MAC_CbackQueryRetransmit(void)
{
  return(0);
}


/**************************************************************************************************
 *
 * @fn      MAC_CbackCheckPending
 *
 * @brief   Returns the number of indirect messages pending in the application
 *
 * @param   None
 *
 * @return  Number of indirect messages in the application
 *
 **************************************************************************************************/
uint8 MAC_CbackCheckPending(void)
{
  return (0);
}


/**************************************************************************************************
 *
 * @fn          MSA_Init
 *
 * @brief       Initialize the application
 *
 * @param       none
 *
 * @return      none
 *
 **************************************************************************************************/
static void MSA_Init(void)
{
  UInt msaWaitPeriod = MSA_WAIT_PERIOD * 1000 / Clock_tickPeriod;
  UInt msaLed4Period = MSA_LED4_INITIAL_PERIOD * 1000 / Clock_tickPeriod;
  
  /* Open LED PIN driver */
  ledPinHandle = PIN_open(&ledPinState, ledPinTable);
  
  /* Initialize clock wait parameters */
  Clock_Params_init(&msaSendParams);
  
  /* Create a one-shot wait timer */
  msaSendParams.period = 0;
  msaSendParams.startFlag = FALSE; 
  msaSendParams.arg = (UArg)MSA_SEND_EVENT;
  Clock_construct(&msaSend, MSA_ClockFxn, msaWaitPeriod, &msaSendParams); 

  /* Initialize clock poll parameters */
  Clock_Params_init(&msaPollParams);
  
  /* Create a periodic poll timer */
  msaPollParams.period = msaWaitPeriod;
  msaPollParams.startFlag = FALSE; 
  msaPollParams.arg = (UArg)MSA_POLL_EVENT;
  Clock_construct(&msaPoll, MSA_ClockFxn, msaWaitPeriod, &msaPollParams); 

  /* Initialize clock poll parameters */
  Clock_Params_init(&msaLed4Params);
  
  /* Create a periodic poll timer */
  msaLed4Params.period = msaLed4Period;
  msaLed4Params.startFlag = TRUE; 
  msaLed4Params.arg = (UArg)MSA_LED4_EVENT;
  Clock_construct(&msaLed4, MSA_ClockFxn, msaLed4Period, &msaLed4Params);

  /* Setup parameters for debounce timeout */
  Clock_Params_init(&msaKeyParams);
  msaKeyParams.period = 0;
  msaKeyParams.startFlag = false;

  /* Keycallback for keys */
  Clock_construct(&msaKey, MSA_keyCB, KEY_DEBOUNCE_TIMEOUT, &msaKeyParams);

  /* Initialize keys */
  MSA_initKeys();
  
  /* Register the current thread as an ICall dispatcher application
   * so that the application can send and receive messages.
   */
  ICall_registerApp(&macAppEntity, &sem);
  
  /* Send a MAC init message */
  MAC_Init();
  
  /* initialize MAC features */
#ifdef MSA_FFD  
  MAC_InitCoord();
#else
  MAC_InitDevice();
#endif
  
  /* Reset the MAC */
  MAC_MlmeResetReq(TRUE);
  
  /* Initialize MAC beacon */
#ifdef MSA_FFD  
  MAC_InitBeaconCoord();
#else
  MAC_InitBeaconDevice();
#endif
 
#ifdef FEATURE_MAC_SECURITY
  /* Initialize the security part of the application */
  MSA_SecurityInit();
#endif /* FEATURE_MAC_SECURITY */

  /* Initialize the data packet */
  for (uint_least8_t i=MSA_HEADER_LENGTH; i<MSA_PACKET_LENGTH; i++)
  {
    msa_Data1[i] = i-MSA_HEADER_LENGTH;
  }

  /* Initialize the echo packet */
  for (uint_least8_t j=0; j<MSA_ECHO_LENGTH; j++)
  {
    msa_Data2[j] = 0xEE;
  }

  msa_BeaconOrder = MSA_MAC_BEACON_ORDER;
  msa_SuperFrameOrder = MSA_MAC_SUPERFRAME_ORDER;
  
#if defined( USE_FPGA )
  /* Send a fake UP key for FPGA to start the association */
  MSA_HandleKeys(Board_KEY_UP);
#endif /* USE_FPGA  */
}


#ifdef FEATURE_MAC_SECURITY
/**************************************************************************************************
 *
 * @fn          MSA_SecurityInit
 *
 * @brief       Initialize the security part of the application
 *
 * @param       none
 *
 * @return      none
 *
 **************************************************************************************************/
void MSA_SecurityInit(void)
{
  uint_least8_t   keyTableEntries      = MSA_KEY_TABLE_ENTRIES;
  uint_least8_t   autoRequestSecLevel  = MAC_SEC_LEVEL_NONE;
  uint_least8_t   securityLevelEntries = MSA_SECURITY_LEVEL_ENTRIES;

  /* Write key table PIBs */
  MAC_MlmeSetSecurityReq(MAC_KEY_TABLE, (void *)msa_keyTable);
  MAC_MlmeSetSecurityReq(MAC_KEY_TABLE_ENTRIES, &keyTableEntries );

  /* Write default key source to PIB */
  MAC_MlmeSetSecurityReq(MAC_DEFAULT_KEY_SOURCE, (void *)msa_keyDefaultSource);

  /* Write security level table to PIB */
  MAC_MlmeSetSecurityReq(MAC_SECURITY_LEVEL_TABLE, (void *)msa_securityLevelTable);
  MAC_MlmeSetSecurityReq(MAC_SECURITY_LEVEL_TABLE_ENTRIES, &securityLevelEntries);

  /* MAC_AUTO_REQUEST is turned on by default. Dieable auto request security. */
  MAC_MlmeSetSecurityReq(MAC_AUTO_REQUEST_SECURITY_LEVEL, &autoRequestSecLevel);

  /* Turn on MAC security */
  MAC_MlmeSetReq(MAC_SECURITY_ENABLED, &macSecurity);
}


/**************************************************************************************************
 *
 * @fn          MSA_SecuredDeviceTableUpdate
 *
 * @brief       Update secured device table and key device descriptor handle
 *
 * @param       panID - Secured network PAN ID
 * @param       shortAddr - Other device's short address
 * @param       extAddr - Other device's extended address
 * @param       pNumOfSecuredDevices - pointer to number of secured devices
 *
 * @return      none
 *
 **************************************************************************************************/
void MSA_SecuredDeviceTableUpdate(uint_least16_t panID,
                                  uint_least16_t shortAddr,
                                  Timac_sAddrExt_t extAddr,
                                  uint_least8_t *pNumOfSecuredDevices)
{
  /* Update key device list */
  msa_keyDeviceList[*pNumOfSecuredDevices].deviceDescriptorHandle = *pNumOfSecuredDevices;

  /* Update device table */
  msa_deviceTable[*pNumOfSecuredDevices].panID = panID;
  msa_deviceTable[*pNumOfSecuredDevices].shortAddress = shortAddr;
  sAddrExtCpy(msa_deviceTable[*pNumOfSecuredDevices].extAddress, extAddr);
  MAC_MlmeSetSecurityReq(MAC_DEVICE_TABLE, msa_deviceTable);

  /* Increase the number of secured devices */
  (*pNumOfSecuredDevices)++;
  MAC_MlmeSetSecurityReq(MAC_DEVICE_TABLE_ENTRIES, pNumOfSecuredDevices);
}
#endif /* FEATURE_MAC_SECURITY */


/**************************************************************************************************
 *
 * @fn      MSA_CoordinatorStartup()
 *
 * @brief   Update the timer per tick
 *
 * @param   n/a
 *
 * @return  None
 *
 **************************************************************************************************/
void MSA_CoordinatorStartup(void)
{
  Timac_MacMlmeStartReq_t  startReq;

  /* Setup MAC_EXTENDED_ADDRESS */
  MAC_MlmeSetReq(MAC_EXTENDED_ADDRESS, &msa_ExtAddr);

  /* Setup MAC_SHORT_ADDRESS */
  MAC_MlmeSetReq(MAC_SHORT_ADDRESS, &msa_CoordShortAddr);

  /* Setup MAC_BEACON_PAYLOAD_LENGTH */
  MAC_MlmeSetReq(MAC_BEACON_PAYLOAD_LENGTH, &msa_BeaconPayloadLen);

  /* Setup MAC_BEACON_PAYLOAD */
  MAC_MlmeSetReq(MAC_BEACON_PAYLOAD, &msa_BeaconPayload);

  /* Enable RX */
  MAC_MlmeSetReq(MAC_RX_ON_WHEN_IDLE, &msa_MACTrue);

  /* Setup MAC_ASSOCIATION_PERMIT */
  MAC_MlmeSetReq(MAC_ASSOCIATION_PERMIT, &msa_MACTrue);

  /* Fill in the information for the start request structure */
  startReq.startTime = 0;
  startReq.panId = msa_PanId;
  startReq.logicalChannel = MSA_MAC_CHANNEL;
  startReq.beaconOrder = msa_BeaconOrder;
  startReq.superframeOrder = msa_SuperFrameOrder;
  startReq.panCoordinator = TRUE;
  startReq.batteryLifeExt = FALSE;
  startReq.coordRealignment = FALSE;
  startReq.realignSec.securityLevel = FALSE;
  startReq.beaconSec.securityLevel = FALSE;

  /* Call start request to start the device as a coordinator */
  MAC_MlmeStartReqMsg(&startReq);
}


/**************************************************************************************************
 *
 * @fn      MSA_DeviceStartup()
 *
 * @brief   Update the timer per tick
 *
 * @param   beaconEnable: TRUE/FALSE
 *
 * @return  None
 *
 **************************************************************************************************/
void MSA_DeviceStartup()
{
  /* Setup Extended address */
  MAC_MlmeSetReq(MAC_EXTENDED_ADDRESS, &msa_ExtAddr);

  /* Setup MAC_BEACON_PAYLOAD_LENGTH */
  MAC_MlmeSetReq(MAC_BEACON_PAYLOAD_LENGTH, &msa_BeaconPayloadLen);

  /* Setup MAC_BEACON_PAYLOAD */
  MAC_MlmeSetReq(MAC_BEACON_PAYLOAD, &msa_BeaconPayload);

  /* Setup PAN ID */
  MAC_MlmeSetReq(MAC_PAN_ID, &msa_PanId);

  /* This device is setup for Direct Message */
  if (msa_IsDirectMsg)
    MAC_MlmeSetReq(MAC_RX_ON_WHEN_IDLE, &msa_MACTrue);
  else
    MAC_MlmeSetReq(MAC_RX_ON_WHEN_IDLE, &msa_MACFalse);

  /* Setup Coordinator short address */
  MAC_MlmeSetReq(MAC_COORD_SHORT_ADDRESS, &msa_AssociateReq.coordAddress.addr.shortAddr);

#ifdef FEATURE_MAC_SECURITY
  /* Setup Coordinator short address for security */
  MAC_MlmeSetSecurityReq(MAC_PAN_COORD_SHORT_ADDRESS, &msa_AssociateReq.coordAddress.addr.shortAddr);
#endif /* FEATURE_MAC_SECURITY */

  if (msa_BeaconOrder != 15)
  {
    /* Setup Beacon Order */
    MAC_MlmeSetReq(MAC_BEACON_ORDER, &msa_BeaconOrder);

    /* Setup Super Frame Order */
    MAC_MlmeSetReq(MAC_SUPERFRAME_ORDER, &msa_SuperFrameOrder);

    /* Sync request */
    MSA_SyncReq();
  }
}


/**************************************************************************************************
 *
 * @fn      MSA_AssociateReq()
 *
 * @brief
 *
 * @param    None
 *
 * @return  None
 *
 **************************************************************************************************/
void MSA_AssociateReq(void)
{
  MAC_MlmeAssociateReqMsg(&msa_AssociateReq);
}


/**************************************************************************************************
 *
 * @fn      MSA_AssociateRsp()
 *
 * @brief   This routine is called by Associate_Ind inorder to return the response to the device
 *
 * @param   pMsg - pointer to the structure recieved by MAC_MLME_ASSOCIATE_IND
 *
 * @return  None
 *
 **************************************************************************************************/
void MSA_AssociateRsp(TimacMSG_MacCbackEvent_t* pMsg)
{
  /* Assign the short address  for the Device, from pool */
  uint_least16_t assocShortAddress = msa_DevShortAddrList[msa_NumOfDevices];
  uint_least16_t panID;

  MAC_MlmeGetReq(MAC_PAN_ID, &panID);

#ifdef FEATURE_MAC_SECURITY
  MSA_SecuredDeviceTableUpdate(panID, assocShortAddress,
                               pMsg->associateInd.deviceAddress,
                               &msa_NumOfSecuredDevices);
#endif /* FEATURE_MAC_SECURITY */
  
  /* Enable Source Matching */
  MAC_SrcMatchEnable();

#ifdef NV_RESTORE
  srcMatchisEnabled = 1;
#endif
  
  /* Build the record for this device */
  msa_DeviceRecord[msa_NumOfDevices].devShortAddr = msa_DevShortAddrList[msa_NumOfDevices];
  msa_DeviceRecord[msa_NumOfDevices].isDirectMsg = pMsg->associateInd.capabilityInformation & MAC_CAPABLE_RX_ON_IDLE;
  msa_NumOfDevices++;

  /* If the number of devices are more than MAX_DEVICE_NUM, turn off the association permit */
  if (msa_NumOfDevices == MSA_MAX_DEVICE_NUM)
    MAC_MlmeSetReq(MAC_ASSOCIATION_PERMIT, &msa_MACFalse);

  /* Fill in association respond message */
  sAddrExtCpy(msa_AssociateRsp.deviceAddress, pMsg->associateInd.deviceAddress);
  msa_AssociateRsp.assocShortAddress = assocShortAddress;
  msa_AssociateRsp.status = MAC_SUCCESS;
  
  msa_AssociateRsp.sec.securityLevel = MAC_SEC_LEVEL_NONE;

  /* Call Associate Response */
  MAC_MlmeAssociateRspMsg(&msa_AssociateRsp);
}


uint8 msa_msdu_data[128]= 
{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40,
 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60,
 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80} ;

/**************************************************************************************************
 *
 * @fn      MSA_McpsDataReq()
 *
 * @brief   This routine calls the Data Request
 *
 * @param   data       - contains the data that would be sent
 *          dataLength - length of the data that will be sent
 *
 * @return  None
 *
 **************************************************************************************************/
void MSA_McpsDataReq(uint8* data, uint8 dataLength, bool directMsg, uint16 dstShortAddr)
{
  Timac_MacMcpsDataReq_t  *pData;
  static  uint_least8_t handle = 0;

  if ((pData = MAC_McpsDataAllocMsg(dataLength, msa_securityLevel, msa_keyIdMode)) != NULL)
  {
//moto START
//Org
#if 0
    pData->mac.srcAddrMode = SADDR_MODE_SHORT;
    pData->mac.dstAddr.addrMode = SADDR_MODE_SHORT;
    pData->mac.dstAddr.addr.shortAddr = dstShortAddr;
    pData->mac.dstPanId = msa_PanId;
    pData->mac.msduHandle = handle++;
    pData->mac.txOptions = MAC_TXOPTION_ACK;
#endif
    
//#if 0
    // DATA LEN=0
    pData->msdu.p = msa_msdu_data;
    pData->msdu.len = 0;
    memcpy( &(pData->internal), 0, sizeof(Timac_MacTxIntData_t) );
    memset(&(pData->sec), 0, sizeof(Timac_MacSec_t));
    pData->sec.securityLevel = 0;
    pData->mac.dstAddr.addrMode = SADDR_MODE_SHORT;
    pData->mac.dstAddr.addr.shortAddr = 0;
    pData->mac.dstPanId = 0;
    pData->mac.srcAddrMode = SADDR_MODE_SHORT;
    pData->mac.msduHandle = handle++;
    pData->mac.txOptions = MAC_TXOPTION_NO_RETRANS | MAC_TXOPTION_PWR_CHAN | MAC_TXOPTION_ALT_BE ;
    pData->mac.channel = MSA_MAC_CHANNEL;
    pData->mac.power = 0;
    pData->mac.gpOffset = 0;
    pData->mac.gpDuration = 0;
//#endif
#if 0
    //DATA LEN=1
    pData->msdu.p = msa_msdu_data;
    pData->msdu.len = 1;
    memcpy( &(pData->internal), 0, sizeof(Timac_MacTxIntData_t) );
    memset(&(pData->sec), 0, sizeof(Timac_MacSec_t));
    pData->sec.securityLevel = 0;
    pData->mac.dstAddr.addrMode = SADDR_MODE_SHORT;
    pData->mac.dstAddr.addr.shortAddr = 0;
    pData->mac.dstPanId = 0;
    pData->mac.srcAddrMode = SADDR_MODE_SHORT;
    pData->mac.msduHandle = handle++;
    pData->mac.txOptions = MAC_TXOPTION_NO_RETRANS | MAC_TXOPTION_PWR_CHAN | MAC_TXOPTION_ALT_BE ;
    pData->mac.channel = MSA_MAC_CHANNEL;
    pData->mac.power = 0;
    pData->mac.gpOffset = 0;
    pData->mac.gpDuration = 0;
#endif
#if 0
    //DATA LEN=127
    pData->msdu.p = msa_msdu_data;
    pData->msdu.len = 116;
    memcpy( &(pData->internal), 0, sizeof(Timac_MacTxIntData_t) );
    memset(&(pData->sec), 0, sizeof(Timac_MacSec_t));
    pData->sec.securityLevel = 0;
    pData->mac.dstAddr.addrMode = SADDR_MODE_SHORT;
    pData->mac.dstAddr.addr.shortAddr = 0;
    pData->mac.dstPanId = 0;
    pData->mac.srcAddrMode = SADDR_MODE_SHORT;
    pData->mac.msduHandle = handle++;
    pData->mac.txOptions = MAC_TXOPTION_NO_RETRANS | MAC_TXOPTION_PWR_CHAN | MAC_TXOPTION_ALT_BE ;
    pData->mac.channel = MSA_MAC_CHANNEL;
    pData->mac.power = 0;
    pData->mac.gpOffset = 0;
    pData->mac.gpDuration = 0;
#endif
#if 0    
    /* MAC security parameters */
    memcpy( pData->sec.keySource, msa_keySource, MAC_KEY_SOURCE_MAX_LEN );
    pData->sec.securityLevel = msa_securityLevel;
    pData->sec.keyIdMode = msa_keyIdMode;
    pData->sec.keyIndex = msa_keyIndex;

    /* If it's the coordinator and the device is in-direct message */
    if (msa_IsCoordinator)
    {
      if (!directMsg)
      {
        pData->mac.txOptions |= MAC_TXOPTION_INDIRECT;
      }
    }

    /* Copy data */
    memcpy (pData->msdu.p, data, dataLength);
#endif
    /* Send out data request */
    MAC_McpsDataReqMsg(pData);
  }
}


/**************************************************************************************************
 *
 * @fn      MSA_McpsPollReq()
 *
 * @brief   Performs a poll request on the coordinator
 *
 * @param   None
 *
 * @return  None
 *
 **************************************************************************************************/
void MSA_McpsPollReq(void)
{
  Timac_MacMlmePollReq_t  pollReq;

  /* Fill in information for poll request */
  pollReq.coordAddress.addrMode = SADDR_MODE_SHORT;
  pollReq.coordAddress.addr.shortAddr = msa_CoordShortAddr;
  pollReq.coordPanId = msa_PanId;
  pollReq.sec.securityLevel = MAC_SEC_LEVEL_NONE;

  /* Call poll reuqest */
  MAC_MlmePollReqMsg(&pollReq);
}


/**************************************************************************************************
 *
 * @fn      MSA_ProcessEvent
 *
 * @brief   Process event from Stack
 *
 * @param   macCbackEvent_t
 *
 * @return  status
 *
 **************************************************************************************************/
 uint_least16_t MSA_ProcessEvent(TimacMSG_MacCbackEvent_t *pMsg)
{
  TimacMSG_MacCbackEvent_t* pData;

#ifdef MSA_FFD
  uint8 j, panflag;
#endif

#if defined(NV_RESTORE) 
#if defined(FEATURE_MAC_SECURITY)
  uint8 i;
#endif
#endif

#ifdef FEATURE_MAC_SECURITY
  uint_least16_t    panID;
  uint_least16_t    panCoordShort;
  Timac_sAddrExt_t  panCoordExtAddr;
#endif /* FEATURE_MAC_SECURITY */
  
  switch (pMsg->hdr.event)
  {
  case MAC_MLME_ASSOCIATE_IND:
    MSA_AssociateRsp((TimacMSG_MacCbackEvent_t *)pMsg);
#ifdef NV_RESTORE
    MAC_NvSrcMatchisEnabled(srcMatchisEnabled);
    MAC_NvCoordSave((deviceRecord *)msa_DeviceRecord, 
                     msa_NumOfDevices, 
                     (uint32)MSA_MAX_DEVICE_NUM,
#ifdef FEATURE_MAC_SECURITY  
                     &msa_deviceTable,
                     &msa_keyTable);
#else
                     NULL,
                     NULL); 
#endif
#endif
    
    break;
    
  case MAC_MLME_ASSOCIATE_CNF:
    /* Retrieve the message */
    pData = (TimacMSG_MacCbackEvent_t *) pMsg;
    
    if ((!msa_IsStarted) && (pData->associateCnf.hdr.status == MAC_SUCCESS))
    {
      msa_IsStarted = TRUE;
      
      /* Retrieve MAC_SHORT_ADDRESS */
      
      msa_DevShortAddr = pData->associateCnf.assocShortAddress;
      
      /* Setup MAC_SHORT_ADDRESS - obtained from Association */
      MAC_MlmeSetReq(MAC_SHORT_ADDRESS, &msa_DevShortAddr);
      
#ifdef FEATURE_MAC_SECURITY
      /* Add the coordinator to device table and key device table for security */
      MAC_MlmeGetReq(MAC_PAN_ID, &panID);
      MAC_MlmeGetSecurityReq(MAC_PAN_COORD_SHORT_ADDRESS, &panCoordShort);
      MAC_MlmeGetSecurityReq(MAC_PAN_COORD_EXTENDED_ADDRESS, &panCoordExtAddr);
      MSA_SecuredDeviceTableUpdate(panID, panCoordShort,
                                   panCoordExtAddr, &msa_NumOfSecuredDevices);
#endif /* FEATURE_MAC_SECURITY */
      
      Clock_stop(Clock_handle(&msaLed4));
      Clock_setPeriod(Clock_handle(&msaLed4), (MSA_LED4_WAIT_PERIOD * 1000/ Clock_tickPeriod));
        
      Clock_start(Clock_handle(&msaLed4));
      
      /* Poll for data if it's not setup for direct messaging */
      if (!msa_IsDirectMsg)
      {
        /* Start the MSA periodic poll timer. */
        Clock_start(Clock_handle(&msaPoll));
      }
#ifdef NV_RESTORE
#ifdef FEATURE_MAC_SECURITY
      MAC_NvDeviceSave(&msa_deviceTable, &msa_keyTable);
#else
      MAC_NvDeviceSave(NULL, NULL);
#endif
#endif
      
    }
    break;
    
  case MAC_MLME_COMM_STATUS_IND:
    break;
    
  case MAC_MLME_BEACON_NOTIFY_IND:
    /* Retrieve the message */
    pData = (TimacMSG_MacCbackEvent_t *) pMsg;
    
    /* Check for correct beacon payload */
    if (!msa_IsStarted && !msa_IsSampleBeacon)
    {
      /* If it's the correct beacon payload and matching PANID, retrieve the data for association req */
      if (MSA_BeaconPayLoadCheck(pData->beaconNotifyInd.pSdu) && 
          (pData->beaconNotifyInd.pPanDesc->coordPanId == msa_PanId))
      {
        msa_IsSampleBeacon = TRUE;
      }

      if (msa_IsSampleBeacon)
      {
        msa_AssociateReq.logicalChannel = MSA_MAC_CHANNEL;
        msa_AssociateReq.coordAddress.addrMode = SADDR_MODE_SHORT;
        msa_AssociateReq.coordAddress.addr.shortAddr = pData->beaconNotifyInd.pPanDesc->coordAddress.addr.shortAddr;
        msa_AssociateReq.coordPanId = pData->beaconNotifyInd.pPanDesc->coordPanId;
        if (msa_IsDirectMsg)
          msa_AssociateReq.capabilityInformation = MAC_CAPABLE_ALLOC_ADDR | MAC_CAPABLE_RX_ON_IDLE;
        else
          msa_AssociateReq.capabilityInformation = MAC_CAPABLE_ALLOC_ADDR;
        msa_AssociateReq.sec.securityLevel = MAC_SEC_LEVEL_NONE;
        
        /* Retrieve beacon order and superframe order from the beacon */
        msa_BeaconOrder = MAC_SFS_BEACON_ORDER(pData->beaconNotifyInd.pPanDesc->superframeSpec);
        msa_SuperFrameOrder = MAC_SFS_SUPERFRAME_ORDER(pData->beaconNotifyInd.pPanDesc->superframeSpec);
      }
    }
    
    break;
    
  case MAC_MLME_START_CNF:
    /* Retrieve the message */
    pData = (TimacMSG_MacCbackEvent_t *) pMsg;
    /* Set some indicator for the Coordinator */
    if ((!msa_IsStarted) && (pData->startCnf.hdr.status == MAC_SUCCESS))
    {
      msa_IsStarted = TRUE;
      msa_IsCoordinator = TRUE;
#ifdef NV_RESTORE
      MAC_NvCoordStartup();
      MAC_NvSrcMatchisEnabled(srcMatchisEnabled);
      MAC_NvCoordSave((deviceRecord *)msa_DeviceRecord, 
                     msa_NumOfDevices, 
                     (uint32)MSA_MAX_DEVICE_NUM,
#ifdef FEATURE_MAC_SECURITY  
                     &msa_deviceTable,
                     &msa_keyTable);
#else
                     NULL,
                     NULL);
#endif
#endif

      Clock_stop(Clock_handle(&msaLed4));
      PIN_setOutputValue(ledPinHandle, Board_LED4, Board_LED_ON);
    }
    break;
    
  case MAC_MLME_SCAN_CNF:     
    /* Check if there is any Coordinator out there */
    pData = (TimacMSG_MacCbackEvent_t *) pMsg;
    
#ifdef MSA_FFD    
    /* If there is no other on the channel or no other with sampleBeacon start as coordinator */
    if (((pData->scanCnf.resultListSize == 0) && (pData->scanCnf.hdr.status == MAC_NO_BEACON)) || (!msa_IsSampleBeacon))
    {
      MSA_CoordinatorStartup();
    }
    else if( pData->scanCnf.resultListSize > 0) 
    {
      panflag = 0;
      /* Go through all the pan descriptors of the recieved beacons to check 
       * for matching PAN ID.
       */
      for(j = 0; j <  pData->scanCnf.resultListSize; j++ )
      {
        if( pData->scanCnf.result.pPanDescriptor[j].coordPanId == msa_PanId )
        {
          panflag = 1;
        }
      }
      
      if(!panflag)
      {
        MSA_CoordinatorStartup();
      }
    }
#else
    if ((msa_IsSampleBeacon) && pData->scanCnf.hdr.status == MAC_SUCCESS)
    {
      /* Start the devive up as beacon enabled or not */
      MSA_DeviceStartup();
#ifdef NV_RESTORE
      MAC_NvDeviceStartup();
#endif

      
      /* Call Associate Req */
      MSA_AssociateReq();
    }
#endif
    msa_IsScanRequest = FALSE;
    break;
    
  case MAC_MCPS_DATA_CNF:
    pData = (TimacMSG_MacCbackEvent_t  *) pMsg;
    
    /* If last transmission completed, ready to send the next one */
    if ((pData->dataCnf.hdr.status == MAC_SUCCESS) ||
        (pData->dataCnf.hdr.status == MAC_CHANNEL_ACCESS_FAILURE) ||
          (pData->dataCnf.hdr.status == MAC_NO_ACK))
    {
      /* Start MSA send event one-shot timer */
      Clock_start(Clock_handle(&msaSend));
    }
    
    MAC_MacMsgDeallocate((TimacMSG_HDR *)pData->dataCnf.pDataReq);
    break;
    
  case MAC_MCPS_DATA_IND:
    pData = (TimacMSG_MacCbackEvent_t *)pMsg;
    
    if (MSA_DataCheck ( pData->dataInd.msdu.p, pData->dataInd.msdu.len ))
    {
      PIN_setOutputValue(ledPinHandle, Board_LED3, !PIN_getOutputValue(Board_LED3));
      
      /* Only send the echo back if the received */
      if (!msa_IsCoordinator)
      {
        if (MSA_ECHO_LENGTH >= 4)
        {
          /* Return the first 4 bytes and the last byte of the received packet */
          msa_Data2[0] = pData->dataInd.msdu.p[0];
          msa_Data2[1] = pData->dataInd.msdu.p[1];
          msa_Data2[2] = pData->dataInd.msdu.p[2];
          msa_Data2[3] = pData->dataInd.msdu.p[3];
        }
        
        MSA_McpsDataReq(msa_Data2,
                        MSA_ECHO_LENGTH,
                        TRUE,
                        msa_CoordShortAddr );
      }
                  
#if defined (NV_RESTORE) && defined(FEATURE_MAC_SECURITY)
      /* Incoming Packet*/
      for(i = 0; i < MAX_DEVICE_TABLE_ENTRIES; i++)
      {
        if (msa_deviceTable[i].shortAddress == pData->dataInd.mac.srcAddr.addr.shortAddr)
        {
          msa_deviceTable[i].frameCounter[0]++;
        }
        if(msa_deviceTable[i].frameCounter[0] % 1000 == 0)
        {
          nv_write(MAC_NV_DEVICE_TABLE, 0, sizeof(msa_deviceTable), &msa_deviceTable); 
        }
      }
#endif

    }
    break;
    
  default:
    break;
  }
  return 0;
}


/**************************************************************************************************
 *
 * @fn      MSA_BeaconPayLoadCheck()
 *
 * @brief   Check if the beacon comes from MSA but not zigbee
 *
 * @param   pSdu - pointer to the buffer that contains the data
 *
 * @return  TRUE or FALSE
 *
 **************************************************************************************************/
bool MSA_BeaconPayLoadCheck(uint_least8_t* pSdu)
{
  uint8 i = 0;
  for (i=0; i<msa_BeaconPayloadLen; i++)
  {
    if (pSdu[i] != msa_BeaconPayload[i])
    {
      return FALSE;
    }
  }

  return TRUE;
}


/**************************************************************************************************
 *
 * @fn      MSA_DataCheck()
 *
 * @brief   Check if the data match with the predefined data
 *
 * @param    data - pointer to the buffer where the data will be checked against the predefined data
 *           dataLength - length of the data
 *
 * @return  TRUE if the data matched else it's the response / echo packet
 *
 **************************************************************************************************/
bool MSA_DataCheck(uint_least8_t* data, uint_least8_t dataLength)
{
  uint_least8_t i = 0;

  if (data[0] == dataLength)
  {
    for (i=MSA_HEADER_LENGTH; i<(data[0] - 1); i++)
    {
       if (data[i] != msa_Data1[i])
       {
         return FALSE;
       }
    }
  }
  else
  {
    return FALSE;
  }
  
  return TRUE;
}


/**************************************************************************************************
 *
 * @fn      MSA_Process
 *
 * @brief   Application task processing start.
 *
 * @param   none
 *
 * @return  void
 *
 **************************************************************************************************/
static void MSA_Process(void)
{
  static uint8 index;
  static uint8 sequence;

  /* Forever loop */
  for (;;)
  {
    ICall_ServiceEnum stackid;
    ICall_EntityID dest;
    TimacMSG_MacCbackEvent_t *pMsg;
    uint16_t events;

    /* Wait for response message */
    if (ICall_wait(ICALL_TIMEOUT_FOREVER) == ICALL_ERRNO_SUCCESS)
    {
      /* Retrieve the response message */
      if (ICall_fetchServiceMsg(&stackid, &dest, (void **) &pMsg)
          == ICALL_ERRNO_SUCCESS)
      {
        if ((stackid == ICALL_SERVICE_CLASS_TIMAC) &&
            (dest == macAppEntity ))
        {

           MSA_ProcessEvent(pMsg);
        }
        
        if (pMsg)
        {
           ICall_freeMsg(pMsg);
        }
      }

      {
        UInt key = Hwi_disable();
        events = msa_events;
        msa_events = 0;
        Hwi_restore(key);
      }

      if(events & MSA_POLL_EVENT)
      {
        MSA_McpsPollReq();
      }
      
      if(events & MSA_LED4_EVENT)
      {
        PIN_setOutputValue(ledPinHandle, Board_LED4, !PIN_getOutputValue(Board_LED4));
      }

      if(events & MSA_KEY_EVENT)
      {
        MSA_HandleKeys(keys);
        keys = 0;
      }
            
      if(events & MSA_SEND_EVENT)
      {
        /* Do it again */
        if (msa_State == MSA_SEND_STATE)
        {
          /* Start sending */
//moto START
          msa_IsCoordinator = 1;
          if (msa_IsCoordinator)
//          if (msa_IsCoordinator)
//moto END
          {
            if (MSA_PACKET_LENGTH >= MSA_HEADER_LENGTH)
            {
              /* Coordinator sending to devices. Use the associated list of device to send out msg */
              msa_Data1[0] = MSA_PACKET_LENGTH;
              msa_Data1[1] = HI_UINT16(msa_DeviceRecord[index].devShortAddr);
              msa_Data1[2] = LO_UINT16(msa_DeviceRecord[index].devShortAddr);
              msa_Data1[3] = sequence;
            }
            
            PIN_setOutputValue(ledPinHandle, Board_LED1, !PIN_getOutputValue(Board_LED1));
            MSA_McpsDataReq((uint8*)msa_Data1,
                            MSA_PACKET_LENGTH,
                            msa_DeviceRecord[index].isDirectMsg,
                            msa_DeviceRecord[index].devShortAddr );
            
            /* Reset the index if it reaches the current number of associated devices */
            if (++index == msa_NumOfDevices)
            {
              index = 0;
            }
          }
          else
          {
            if (MSA_PACKET_LENGTH >= MSA_HEADER_LENGTH)
            {
              /* Device sending to coordinator */
              msa_Data1[0] = MSA_PACKET_LENGTH;
              msa_Data1[1] = HI_UINT16(msa_CoordShortAddr);
              msa_Data1[2] = LO_UINT16(msa_CoordShortAddr);
              msa_Data1[3] = sequence;
            }
            PIN_setOutputValue(ledPinHandle, Board_LED1, !PIN_getOutputValue(Board_LED1));
            MSA_McpsDataReq((uint8*)msa_Data1,
                            MSA_PACKET_LENGTH,
                            TRUE,
                            msa_CoordShortAddr );
            
          }

#if defined (NV_RESTORE) && defined (FEATURE_MAC_SECURITY)
          msa_keyTable[0].frameCounter++;
      
          if(msa_keyTable[0].frameCounter % 1000 == 0)
          {
            nv_write(MAC_NV_KEY_TABLE, 0, sizeof(msa_keyTable), &msa_keyTable); 
          }
#endif /* defined (NV_RESTORE) && defined (FEATURE_MAC_SECURITY) */

          
          if (sequence++ == 0xFF)
          {
            sequence = 0;
          }
          
//          PIN_setOutputValue(ledPinHandle, Board_LED1, !PIN_getOutputValue(Board_LED1));
        }
      }
    }
  }
}


/**************************************************************************************************
 *
 * @fn      msa_task
 *
 * @brief   Application task entry point for the TIMAC Sample Appication.
 *
 * @param   none
 *
 * @return  void
 *
 **************************************************************************************************/
void msa_task(void)
{
  /* Initialize application */
  MSA_Init();
  
#ifdef NV_RESTORE
  IntMasterDisable();
  MSA_NvRestore();
  IntMasterEnable();
#endif
  
#ifdef PA_LNA_CC2592
  {
    int8 power = 20;

    /* Set TX power */
    MAC_MlmeSetReq(MAC_PHY_TRANSMIT_POWER_SIGNED, &power);
  }
#endif /* PA_LNA_CC2592 */  
  
  /* No return from MSA process */
  MSA_Process();
}


/**************************************************************************************************
 *
 * @fn      MSA_ClockFxn
 *
 * @brief   MSA Clock Callback function.
 *
 * @param   param - parameter passed in
 *
 * @return  void
 *
 **************************************************************************************************/
static void MSA_ClockFxn(UArg param)
{
  msa_events |= (uint16_t) param;
  
  /* Semophore post to self */
  Semaphore_post(sem);
}


/**************************************************************************************************
 *
 * @fn      MSA_HandleKeys
 *
 * @brief   Callback service for keys
 *
 * @param   keys  - keys that were pressed
 *          state - shifted
 *
 * @return  void
 *
 **************************************************************************************************/
void MSA_HandleKeys(uint_least8_t keys)
{
  if ( keys == Board_KEY_UP )
  {
    /* Start the device as a direct message device and beacon disabled*/
    if (!msa_IsStarted && !msa_IsScanRequest)
    {
      /* Decide if direct or indirect messaging is used */
      msa_IsDirectMsg = MSA_DIRECT_MSG_ENABLED;

      if (msa_IsDirectMsg)
      {
         msa_IsScanRequest = TRUE;
        /* Start the device as an DIRECT messaging device */
        if (msa_BeaconOrder != 15)
          MSA_ScanReq(MAC_SCAN_PASSIVE, MSA_MAC_BEACON_ORDER + 1);
        else
          MSA_ScanReq(MAC_SCAN_ACTIVE, 3);
      }
      else
      {
        /* Start the device as an INDIRECT messaging device and beacon disabled */
         /* Beacon network doesn't work with polling */
         if (!msa_IsStarted)
         {
           msa_IsScanRequest = TRUE; 
           msa_IsDirectMsg = FALSE;
           MSA_ScanReq(MAC_SCAN_ACTIVE, 3);
         }
      }
    }
  }

  if ( keys == Board_KEY_RIGHT || keys == Board_KEY_SELECT )
  {
    /* Start sending message */
    if (msa_IsStarted)
    {
      /* Set App's state to SEND or IDLE */
      if (msa_State == MSA_IDLE_STATE)
        msa_State = MSA_SEND_STATE;
      else
        msa_State = MSA_IDLE_STATE;

      /* Send Event to the App to carry out the changes */
      Clock_start(Clock_handle(&msaSend));
    }
  }
}

/*********************************************************************
 * @fn      MSA_initKeys
 *
 * @brief   function to enable interrupts for keys on GPIOs
 *
 * @param   none
 *
 * @return  none
 */
static void MSA_initKeys(void)
{
  /* Setup KEY ISR */
  keyPinHandle = PIN_open(&keyPinState, keyPinTable);
  
  /* Register Callbacks */
  PIN_registerIntCb(keyPinHandle, keyFxn);  
}

/*********************************************************************
 * @fn      MSA_keyCB
 *
 * @brief   Key event handler function
 *
 * @param   a0 - ignored
 *
 * @return  none
 */
void MSA_keyCB(UArg a0)
{
  /* debounce timer has expired - read pin and if still asserted,
   * let the event go through
   */
  if (PIN_getInputValue(keys) == 0)
  {
    /* key is still asserted, so go ahead and process it */
    msa_events |= MSA_KEY_EVENT;

    /* Wake up the application thread when it waits for clock event */
    Semaphore_post(sem);
  }
  else
  {
    /* throw it away */
    keys = 0;
  }
}

/*********************************************************************
 * @fn      keyFxn
 *
 * @brief   Interrupt handler for a Key press
 *
 */
void keyFxn(PIN_Handle keyPinHandle, PIN_Id keyPinId)
{
  (void)keyPinHandle;
  
  keys = keyPinId;
  Clock_start(Clock_handle(&msaKey));
}

/**************************************************************************************************
 *
 * @fn      MSA_NvRestore
 *
 * @brief   Restores NV if the end device or coordinator has been in the network 
 *          before
 *
 * @param   keys  - keys that were pressed
 *          state - shifted
 *
 * @return  void
 *
 **************************************************************************************************/
#if defined(NV_RESTORE) 
void MSA_NvRestore(void)
{
  uint8 macNvInitializedFlag = 0;
  
  if( NV_ITEM_UNINIT == nv_item_init(MAC_NV_INITIALIZED, 
                                          sizeof(macNvInitializedFlag), NULL))
  {
    nv_write(MAC_NV_INITIALIZED, 0, 
                  sizeof(macNvInitializedFlag), &macNvInitializedFlag);
  }
  
  nv_read(MAC_NV_INITIALIZED, 0, 
               sizeof(macNvInitializedFlag), &macNvInitializedFlag);
  
  /* Check if SW_1 was pressed at startup */
  if (PIN_getInputValue(Board_KEY_UP) == 0)
  {
    /* Clear NV */
    MSA_NvReset();
  }
  else
  {
    if(macNvInitializedFlag == 1)
    {
#ifdef MSA_FFD
      /* Restore the network settings of the Coordinator */
      MAC_NvCoordRestore(&msa_ExtAddr,
                         &msa_PanId,
                         (deviceRecord *)msa_DeviceRecord,
                         &msa_NumOfDevices,
                         MSA_MAX_DEVICE_NUM,
#ifdef FEATURE_MAC_SECURITY   
                         &msa_NumOfSecuredDevices,
                         &msa_deviceTable,
                         &msa_keyTable);
#else
                         NULL,
                         NULL,
                         NULL);
      
#endif 
      
#else  //MSA_FFD 
      /* Restore the network settings of the Device */
      MAC_NvDeviceRestore(&msa_ExtAddr,
                          &msa_PanId,
                          &msa_AssociateReq.coordAddress.addr.shortAddr,
                          &msa_DevShortAddr,
#ifdef FEATURE_MAC_SECURITY
                          &msa_NumOfSecuredDevices,
                          &msa_deviceTable,
                          &msa_keyTable);
#else
                          NULL,
                          NULL,
                          NULL);
#endif 
#endif //MSA_FFD
      /* Restore all Application related flags */
      msa_IsStarted = TRUE;
      msa_IsDirectMsg = MSA_DIRECT_MSG_ENABLED;
      
      /* Kick of the coordinator or Device Startup */
#ifdef MSA_FFD
      msa_IsCoordinator = TRUE;
      /* Coordinator Startup */
      MSA_CoordinatorStartup();
#else
      /* Device Startup */
      MSA_DeviceStartup();
      
      /* Poll for data if it's not setup for direct messaging */
      if (!msa_IsDirectMsg)
      {
        /* Start the MSA periodic poll timer. */
        Clock_start(Clock_handle(&msaPoll));
      }
#endif
    }
  }
}
#endif


/**************************************************************************************************
 *
 * @fn      MSA_NvReset
 *
 * @brief   Resets the NV to default PIB and security PIB
 *
 * @param   None
 *
 * @return  None
 *
 **************************************************************************************************/

#ifdef NV_RESTORE
static void MSA_NvReset(void)
{
  uint8 i;
#ifdef MSA_FFD
  MAC_NvCoordClear((deviceRecord *)msa_DeviceRecord, 
                   msa_NumOfDevices, 
                   (uint32)MSA_MAX_DEVICE_NUM);
  MAC_InitBeaconCoord();
#else
  MAC_NvDeviceClear();
  MAC_InitBeaconDevice();
#endif

#ifdef FEATURE_MAC_SECURITY
  /* Initialize the security part of the application */
  MSA_SecurityInit();
#endif /* FEATURE_MAC_SECURITY */
  
  /* Initialize the data packet */
  for (i=MSA_HEADER_LENGTH; i<MSA_PACKET_LENGTH; i++)
  {
    msa_Data1[i] = i-MSA_HEADER_LENGTH;
  }
  
  /* Initialize the echo packet */
  for (i=0; i<MSA_ECHO_LENGTH; i++)
  {
    msa_Data2[i] = 0xEE;
  }
  
  msa_BeaconOrder = MSA_MAC_BEACON_ORDER;
  msa_SuperFrameOrder = MSA_MAC_SUPERFRAME_ORDER;
  msa_NumOfDevices = 0;
  
#ifdef FEATURE_MAC_SECURITY
  /* Current number of devices (including coordinator) communicating to this device */
  msa_NumOfSecuredDevices = 0;
#endif
  msa_IsStarted = FALSE;
}
#endif

/**************************************************************************************************
 **************************************************************************************************/
