/******************************************************************************
  Filename:       GenericApp.c
  Revised:        $Date: 2014-09-07 13:36:30 -0700 (Sun, 07 Sep 2014) $
  Revision:       $Revision: 40046 $

  Description:    Generic Application (no Profile).


  Copyright 2004-2014 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 揂S 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.
******************************************************************************/

/*********************************************************************
  This application isn't intended to do anything useful - it is
  intended to be a simple example of an application's structure.

  This application periodically sends a "Hello World" message to
  another "Generic" application (see 'txMsgDelay'). The application
  will also receive "Hello World" packets.

  This application doesn't have a profile, so it handles everything
  directly - by itself.

  Key control:
    SW1:  changes the delay between TX packets
    SW2:  initiates end device binding
    SW3:
    SW4:  initiates a match description request
*********************************************************************/

/*********************************************************************
 * INCLUDES
 */
#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "ZDObject.h"
#include "ZDProfile.h"
#include "sapi.h"

#include "GenericApp.h"
#include "DebugTrace.h"
#include <string.h>
#include <stdio.h>
#include "OSAL_Nv.h"
#include "GenericAppUart.h" 
#include "Coordinator.h"

#if !defined( WIN32 ) || defined( ZBIT )
  #include "OnBoard.h"
#endif

/* HAL */
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_key.h"
#include "hal_uart.h"

   


/*********************************************************************
 * MACROS
 */

/*********************************************************************
 * CONSTANTS
 */

/*********************************************************************
 * TYPEDEFS
 */

/*********************************************************************
 * GLOBAL VARIABLES
 */
// This list should be filled with Application specific Cluster IDs.
const cId_t GenericApp_ClusterList[GENERICAPP_MAX_CLUSTERS] =
{
  GENERICAPP_CLUSTERID,
  GENERICAPP_DATAUP,
  GENERICAPP_DATADOWN
};

const SimpleDescriptionFormat_t GenericApp_SimpleDesc =
{
  GENERICAPP_ENDPOINT,              //  int Endpoint;
  GENERICAPP_PROFID,                //  uint16 AppProfId[2];
  GENERICAPP_DEVICEID,              //  uint16 AppDeviceId[2];
  GENERICAPP_DEVICE_VERSION,        //  int   AppDevVer:4;
  GENERICAPP_FLAGS,                 //  int   AppFlags:4;
  GENERICAPP_MAX_CLUSTERS,          //  byte  AppNumInClusters;
  (cId_t *)GenericApp_ClusterList,  //  byte *pAppInClusterList;
  GENERICAPP_MAX_CLUSTERS,          //  byte  AppNumInClusters;
  (cId_t *)GenericApp_ClusterList   //  byte *pAppInClusterList;
};

// This is the Endpoint/Interface description.  It is defined here, but
// filled-in in GenericApp_Init().  Another way to go would be to fill
// in the structure here and make it a "const" (in code space).  The
// way it's defined in this sample app it is define in RAM.
endPointDesc_t GenericApp_epDesc;


/*********************************************************************
 * EXTERNAL VARIABLES
 */

/*********************************************************************
 * EXTERNAL FUNCTIONS
 */

/*********************************************************************
 * LOCAL VARIABLES
 */
byte GenericApp_TaskID;   // Task ID for internal task/event processing
                          // This variable will be received when
                          // GenericApp_Init() is called.

devStates_t GenericApp_NwkState;

byte GenericApp_WirelessID;  // This is the unique message ID (counter)

afAddrType_t GenericApp_DstAddr;

static byte    SendFinish;             //发送接收一次



// Number of recieved messages
//static uint16 rxMsgCount;

// Time interval between sending messages
//static uint32 txMsgDelay = GENERICAPP_SEND_MSG_TIMEOUT;

/*********************************************************************
 * @fn      Variable_Init
 *
 * @brief   
 *
 * @param   
 *
 * @return  none
 */
void Variable_Init(uint8 task_id)
{
  GenericApp_TaskID = task_id;
  GenericApp_NwkState = DEV_INIT;
  GenericApp_WirelessID = 0;
  
  GenericApp_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;
  GenericApp_DstAddr.endPoint = GENERICAPP_ENDPOINT;
  GenericApp_DstAddr.addr.shortAddr = 0xFFFD;           //向非睡眠节点

  GenericApp_epDesc.endPoint = GENERICAPP_ENDPOINT;
  GenericApp_epDesc.task_id = &GenericApp_TaskID;
  GenericApp_epDesc.simpleDesc
            = (SimpleDescriptionFormat_t *)&GenericApp_SimpleDesc;
  GenericApp_epDesc.latencyReq = noLatencyReqs;
  SendFinish=SUCCESS;
}


/*********************************************************************
 * @fn      LED_Init
 *
 * @brief   
 *
 * @param   
 *
 * @return  none
 */
void LED_Init(void)
{
  HAL_TURN_OFF_LED1();
  HAL_TURN_OFF_LED2();
  HAL_TURN_OFF_LED3();  
}

/*********************************************************************
 * @fn      Uart1_Init
 *
 * @brief   
 *
 * @param   
 *
 * @return  none
 */
void Uart1_Init(uint8 task_id)
{
    GenericApp_UartInit();//硬件初始化
}
/*********************************************************************
 * @fn      Uart1_SendInit
 *
 * @brief   
 *
 * @param   
 *
 * @return  none
 */
static void Uart1_SendInit()
{
#ifdef Printf_Init
  printf("..........Coodinator is run !..........\r\n");
#endif
}

/*********************************************************************
 * @fn      ZDO_Register
 *
 * @brief   
 *
 * @param   
 *
 * @return  none
 */
void ZDO_Register(uint8 task_id)
{
  ZDO_RegisterForZDOMsg( task_id, End_Device_Bind_rsp );
  ZDO_RegisterForZDOMsg( task_id, Match_Desc_rsp );
}
 

/*********************************************************************
 * @fn      GenericApp_ProcessEvent
 *
 * @brief   Generic Application Task event processor.  This function
 *          is called to process all events for the task.  Events
 *          include timers, messages and any other user defined events.
 *
 * @param   task_id  - The OSAL assigned task ID.
 * @param   events - events to process.  This is a bit map and can
 *                   contain more than one event.
 *
 * @return  none
 */
uint16 GenericApp_ProcessEvent( uint8 task_id, uint16 events )
{
  afIncomingMSGPacket_t *MSGpkt;
//	afDataConfirm_t *afDataConfirm;

  (void)task_id;  // Intentionally unreferenced parameter
//  halIntState_t intState;

  if ( events & SYS_EVENT_MSG )					//系统消息处理
  {
      MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
      while ( MSGpkt )
      {
          switch ( MSGpkt->hdr.event )
          {
              case ZDO_STATE_CHANGE:				//ZDO层状态改变事件
              {
                GenericApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
//                if ( (GenericApp_NwkState == DEV_ZB_COORD) ||
//                         (GenericApp_NwkState == DEV_ROUTER) ||
//                         (GenericApp_NwkState == DEV_END_DEVICE) )
                if(GenericApp_NwkState == DEV_ZB_COORD)
                {
                  TOGGLE_GREE_LED();
                  #ifdef  SysReset
                  osal_start_timerEx(task_id,SYSTERM_RESET_EVENT,(uint32)SYSTEM_RESTART_TIME);
                  #endif
                  // Start sending "the" message in a regular interval.
                }
                else if(GenericApp_NwkState == DEV_NWK_ORPHAN)
                {
                  TOGGLE_GREE_LED();
                  ZDO_Init();
                }
              }
              break;			
              case AF_DATA_CONFIRM_CMD:           //AF层确认帧
              {
                
              }
              break;
              case AF_INCOMING_MSG_CMD:           //AF层数据帧
              {  
                  #ifndef MYLED
                  TOGGLE_GREE_LED();
                  #else
                  TOGGLE_RED_LED();
                  #endif
                  GenericApp_MessageMSGCB(MSGpkt);//AF层数据处理
              }
              break;
              case GENERICAPP_SERIAL_MSG:         //收到串口数据
              {  
                  GenericAppOSALSerialData_addr* uartdata=(GenericAppOSALSerialData_addr*)(MSGpkt);
                  if(uartdata->len<100)
                  UartDataProces((uint8*)&uartdata->msg,uartdata->len);         //串口数据处理
              }
              break;              
              default:
              break;
          }
          osal_msg_deallocate( (uint8 *)MSGpkt );
          MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
      }
      // return unprocessed events
      return (events ^ SYS_EVENT_MSG);
  }  
  if(events & SEND_CHECK_EVENT)               //无线发送事件
  {
      if(SendFinish!=SUCCESS)//未收到服务器应答
      {
         SendFinish=SUCCESS;
      }
      #ifdef  SysReset      
      SystemResetSoft(); 
      #endif
      return(events ^ SEND_CHECK_EVENT);
  }    
  #ifdef  SysReset
  if(events & SYSTERM_RESET_EVENT)               //系统重启事件
  { 
       events ^= SYSTERM_RESET_EVENT;
       SystemReset();   //看门狗重启 2016年5月27日 11:44:28
       return(events ^ SYSTERM_RESET_EVENT);
  }
  #endif

  return 0;  
}

/*********************************************************************
 * @fn      GenericAppGetCardIDFromData
 *
 * @brief   从数据中提取出ID，并把ID返回
 *          
 *
 * @param   pkt：       数据指针
 *
 * @return  CardID
 */
static uint32 GenericAppGetCardIDFromData(CardDataFormat_t* data)
{
  if(data->DataHead==DATA_HEAD)
  {
    uint32 cardID = BUILD_UINT32(data->CardID[3],
                                 data->CardID[2],
                                 data->CardID[1],
                                 data->CardID[0]);
    return cardID;
  }
  else
    return NULL;
}

/*********************************************************************
 * @fn      UartDataFrameOut
 *
 * @brief   挑选一组数据
 *          is called to process all events for the task.  Events
 *          include timers, messages and any other user defined events.
 *
 * @param   pkt：       待发送数据指针
 * @param   len：       待发送数据长度
 * @param   
 * @param   
 *
 * @return  数据组个数
 */
static void UartDataFrameOut(CardDataFormat_t* pkt,uint16 len)//
{
//    uint8 l=0;
//    uint8 repeatnum=0;
//    do
//    {
//      uint8* p=((uint8*)pkt+l);
//      CardDataFormat_t* p1=(CardDataFormat_t*)p;
//      if(p1->DataHead==DATA_HEAD)
//      {
//         WirelessSendUartData(p1,p1->DataLen+3);
//         l+=p1->DataLen+3;
//      }
//      else
//      {
//        l++;
//      }
//    }while(l<len);
      WirelessSendUartData(pkt,len);
}

static uint8 WirelessSendUartData(CardDataFormat_t* pkt,uint16 len)//Uart  数据 发送到 无线
{
  uint32 cardID=GenericAppGetCardIDFromData(pkt);
//  if(cardID != NULL)
  {        
      AF_DataRequest( &GenericApp_DstAddr, 
                      &GenericApp_epDesc,
                       GENERICAPP_DATADOWN,
                       len,
                       (uint8*)pkt,
                       &GenericApp_WirelessID,
                       AF_DISCV_ROUTE, 
                       AF_DEFAULT_RADIUS );
      GenericApp_WirelessID++;
      if(GenericApp_WirelessID==0xFF)
      {
          GenericApp_WirelessID=0;//防止溢出 
      }        
      TOGGLE_GREE_LED();
      SendFinish=SUCCESS;//发送标志完成 2016年6月2日 09:18:02
      #ifdef  SysReset
      osal_stop_timerEx(GenericApp_TaskID,SEND_CHECK_EVENT);
      //          osal_start_reload_timer(GenericApp_TaskID,SYSTERM_RESET_EVENT,(uint32)SYSTEM_RESTART_TIME);         
      #endif        
      return SUCCESS;
  }
//  else 
//    return FAILURE;  
}

/*********************************************************************
 * @fn      GenericAppWirelessSendData
 *
 * @brief   UART 数据从 无线发射出去
 *          is called to process all events for the task.  Events
 *          include timers, messages and any other user defined events.
 *
 * @param   pkt：       待发送数据指针
 * @param   len：       待发送数据长度
 * @param   DataType：  发送数据类型 包含  上行 和  下行
 * @param   TargetAddr：目标地址
 *
 * @return  none
 */
static void GenericAppWirelessSendData(CardDataFormat_t* pkt,uint16 len)//Uart  数据 发送到 无线
{
  UartDataFrameOut(pkt,len);
}


/*********************************************************************
 * @fn      Check_Data_Response
 *
 * @brief   
 *
 * @param   none
 *
 * @return  none
 */
static uint8 Check_Data_Response(afIncomingMSGPacket_t *pkt)  //判断应答是否正确
{
  if(pkt->cmd.DataLength>10)
  {
    uint32 cardID=GenericAppGetCardIDFromData((CardDataFormat_t*)pkt->cmd.Data);
    if(cardID != NULL)
    {         
      return SUCCESS;
    }
    else
      return FAILURE;    
  }
  else
    return FAILURE;
}


/*********************************************************************
 * @fn      GenericApp_MessageMSGCB
 *
 * @brief   Data message processor callback.  This function processes
 *          any incoming data - probably from other devices.  So, based
 *          on cluster ID, perform the intended action.
 *
 * @param   afIncomingMSGPacket_t *pkt
 *
 * @return  none
 */
static void GenericApp_MessageMSGCB(afIncomingMSGPacket_t *pkt )
{
  switch ( pkt->clusterId )
  {
    case GENERICAPP_CLUSTERID:
      {
          GenericApp_DstAddr.addr.shortAddr = pkt->srcAddr.addr.shortAddr;
          if ( AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
                             GENERICAPP_CLUSTERID,
                             (byte)pkt->cmd.DataLength,
                             (byte *)pkt->cmd.Data,
                             &GenericApp_WirelessID,
                             AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )  
          {
            GenericApp_WirelessID++;
            if(GenericApp_WirelessID==0xFF)
                    GenericApp_WirelessID=0;//防止溢出
          // Successfully requested to be sent.
          }
          else
          {
          // Error occurred in request to send.
          }         
      }
      break;  
      case GENERICAPP_DATAUP:       //数据为上行模式  节点发送给路由
        {
            if(Check_Data_Response(pkt)==SUCCESS)
            //查找节点地址并保存 大于存储空间则丢弃
            {
              /******1、收取数据
                     2、触发串口发送事件*******/
//                UartDataProces(pkt->cmd.Data,pkt->cmd.DataLength);//tiaoshi
                if(GenericApp_UartSendData(pkt->cmd.Data,pkt->cmd.DataLength)==SUCCESS)
                {
                  if(SendFinish==SUCCESS)//允许发送数据到服务器  上一组数据已经处理完毕
                  {
                    SendFinish=FAILURE;//发送状态改为失败状态表示数据上传到服务器
                    osal_start_timerEx(GenericApp_TaskID,
                                       SEND_CHECK_EVENT,
                                       (uint32)SERVER_ANSWER_TIME);                    
                  }                  
                  #ifdef MYLED
                  TOGGLE_RED_LED();
                  #endif       
                } 
            }
        }
        break; 
      default:break;		
  }
}

/*********************************************************************
 * @fn      GenericApp_UartSendData
 *
 * @brief   Send data.
 *
 * @param   GenericAppOSALSerialData_addr* ptk
 *
 * @return  发送状态
 */
static uint8 GenericApp_UartSendData(uint8* data,uint16 len)//数据 发送到 Uart
{
    if(HalUARTWrite ( GenericApp_UART_DEFAULT_PORT,data,len) == len)//发送成功  
    {
      return SUCCESS;
    }
    else//发送成功
    {
      return FAILURE;
    }
}
/*********************************************************************
 * @fn      UartDataProces
 *
 * @brief   UartDataProces
 *
 * @param   GenericAppOSALSerialData_addr* Data
 *
 * @return  none
 */
static void UartDataProces(uint8* Data,uint16 len)
{
   GenericAppWirelessSendData((CardDataFormat_t*)Data,len);
}

/*********************************************************************
 * @fn      Uart1_Init_Operation
 * @brief   
 * @param   
 * @return  none
 */

static void Uart1_Init_Operation(uint8 task_id)
{
  Uart1_Init(task_id);                     //Uart1初始化
  UartRegister(task_id);		   //硬件层事件注册  
  Uart1_SendInit();                        //Uart1提示信息输出  
}


/*********************************************************************
 * @fn      GenericApp_Init
 *
 * @brief   Initialization function for the Generic App Task.
 *          This is called during initialization and should contain
 *          any application specific initialization (ie. hardware
 *          initialization/setup, table initialization, power up
 *          notificaiton ... ).
 *
 * @param   task_id - the ID assigned by OSAL.  This ID should be
 *                    used to send messages and set timers.
 *
 * @return  none
 */
void GenericApp_Init( uint8 task_id )
{
  Variable_Init(task_id);		   //变量初始化
  afRegister( &GenericApp_epDesc );        //AF 层注册
  LED_Init();		                   //Led初始化
  ZDO_Register(task_id);		   //ZDO层任务注册
  Uart1_Init_Operation(task_id);           //Uart1 初始化操作
  ZMacSetTransmitPower(TX_PWR_PLUS_21);    //修改发射功率
}