/*********************************************************************
 * INCLUDES
 */

#include "bcomdef.h"
#include "OSAL.h"
#include "OSAL_PwrMgr.h"

#include "OnBoard.h"
#include "hal_adc.h"
#include "hal_led.h"
#include "hal_key.h"
#include "hal_lcd.h"

#include "hci.h"
#include "gap.h"

#include "devinfoservice.h"
#include "broadcaster.h"


#include "xxx.h"


#include "simpleBLEBroadcaster.h"
#ifdef DEBUG_UART
#include "debug_msg.h"
#include "serialInterface.h"
#include <string.h>
#endif
#include "osal_snv.h"

/*********************************************************************
 * MACROS
 */

/*********************************************************************
 * CONSTANTS
 */

// What is the advertising interval when device is discoverable (units of 625us, 160=100ms)
#define DEFAULT_ADVERTISING_INTERVAL          160

// Company Identifier: Texas Instruments Inc. (13)
#define TI_COMPANY_ID                         0x000D

// Length of bd addr as a string
#define B_ADDR_STR_LEN                        15

#define BLE_NVID_ADV 0x80
#define BLE_NVID_RSP 0x81

/*********************************************************************
 * TYPEDEFS
 */

/*********************************************************************
 * GLOBAL VARIABLES
 */

/*********************************************************************
 * EXTERNAL VARIABLES
 */

/*********************************************************************
 * EXTERNAL FUNCTIONS
 */

/*********************************************************************
 * LOCAL VARIABLES
 */


static uint8 simpleBLEBroadcaster_TaskID;   // Task ID for internal task/event processing

// GAP - SCAN RSP data (max size = 31 bytes)
static uint8 scanRspData[30] =
{
  0
  // complete name
  /*0x15,   // length of this data
  GAP_ADTYPE_LOCAL_NAME_COMPLETE,
  0x53,   // 'S'
  0x69,   // 'i'
  0x6d,   // 'm'
  0x70,   // 'p'
  0x6c,   // 'l'
  0x65,   // 'e'
  0x42,   // 'B'
  0x4c,   // 'L'
  0x45,   // 'E'
  0x42,   // 'B'
  0x72,   // 'r'
  0x6f,   // 'o'
  0x61,   // 'a'
  0x64,   // 'd'
  0x63,   // 'c'
  0x61,   // 'a'
  0x73,   // 's'
  0x74,   // 't'
  0x65,   // 'e'
  0x72,   // 'r'

  // Tx power level
  0x02,   // length of this data
  GAP_ADTYPE_POWER_LEVEL,
  0       // 0dBm  */
};

static uint8 def_scanRspData[]=
{
  0x15,   // length of this data
  GAP_ADTYPE_LOCAL_NAME_COMPLETE,
  0x53,   // 'S'
  0x69,   // 'i'
  0x6d,   // 'm'
  0x70,   // 'p'
  0x6c,   // 'l'
  0x65,   // 'e'
  0x42,   // 'B'
  0x4c,   // 'L'
  0x45,   // 'E'
  0x42,   // 'B'
  0x72,   // 'r'
  0x6f,   // 'o'
  0x61,   // 'a'
  0x64,   // 'd'
  0x63,   // 'c'
  0x61,   // 'a'
  0x73,   // 's'
  0x74,   // 't'
  0x65,   // 'e'
  0x72,   // 'r'

  // Tx power level
  0x02,   // length of this data
  GAP_ADTYPE_POWER_LEVEL,
  0       // 0dBm    
};
// GAP - Advertisement data (max size = 31 bytes, though this is
// best kept short to conserve power while advertisting)
static uint8 advertData[30] = 
{ 
  0
  // Flags; this sets the device to use limited discoverable
  // mode (advertises for 30 seconds at a time) instead of general
  // discoverable mode (advertises indefinitely)
  /*0x02,   // length of this data
  GAP_ADTYPE_FLAGS,
  GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,

  // three-byte broadcast of the data "1 2 3"
  0x04,   // length of this data including the data type byte
  GAP_ADTYPE_MANUFACTURER_SPECIFIC,      // manufacturer specific advertisement data type
  1,
  2,
  3*/
};

static uint8 def_advertData[]=
{
  0x02,   // length of this data
  GAP_ADTYPE_FLAGS,
  GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,

  // three-byte broadcast of the data "1 2 3"
  0x04,   // length of this data including the data type byte
  GAP_ADTYPE_MANUFACTURER_SPECIFIC,      // manufacturer specific advertisement data type
  1,
  2,
  3
};
/*********************************************************************
 * LOCAL FUNCTIONS
 */
static void simpleBLEBroadcaster_ProcessOSALMsg( osal_event_hdr_t *pMsg );
static void peripheralStateNotificationCB( gaprole_States_t newState );

#if defined( CC2540_MINIDK )
static void simpleBLEBroadcaster_HandleKeys( uint8 shift, uint8 keys );
#endif

#if (defined HAL_LCD) && (HAL_LCD == TRUE) 
static char *bdAddr2Str ( uint8 *pAddr );
#endif // (defined HAL_LCD) && (HAL_LCD == TRUE) 
#ifdef DEBUG_UART
   deg_msg_t  *deg_msg=0;
#endif
/*********************************************************************
 * PROFILE CALLBACKS
 */

// GAP Role Callbacks
static gapRolesCBs_t simpleBLEBroadcaster_BroadcasterCBs =
{
  peripheralStateNotificationCB,  // Profile State Change Callbacks
  NULL                            // When a valid RSSI is read from controller (not used by application)
};

/*********************************************************************
 * PUBLIC FUNCTIONS
 */

/*********************************************************************
 * @fn      SimpleBLEBroadcaster_Init
 *
 * @brief   Initialization function for the Simple BLE Broadcaster 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 SimpleBLEBroadcaster_Init( uint8 task_id )
{
  simpleBLEBroadcaster_TaskID = task_id;

  // Setup the GAP Broadcaster Role Profile
  {
    #if defined( CC2540_MINIDK )   
      // For the CC2540DK-MINI keyfob, device doesn't start advertising until button is pressed
      uint8 initial_advertising_enable = FALSE;
    #else
      // For other hardware platforms, device starts advertising upon initialization
      uint8 initial_advertising_enable = TRUE;
    #endif

     osal_snv_init();
     HAL_ASSERT( osal_snv_read( BLE_NVID_ADV, sizeof( advertData ), &advertData ) == SUCCESS);   
     HAL_ASSERT( osal_snv_read( BLE_NVID_RSP, sizeof( scanRspData ), &scanRspData )== SUCCESS);    

     if(advertData[0] == 0x00)
       memcpy(advertData,def_advertData,sizeof(def_advertData));
     if(scanRspData[0] == 0x00)
       memcpy(scanRspData,def_scanRspData,sizeof(def_scanRspData));

    // By setting this to zero, the device will go into the waiting state after
    // being discoverable for 30.72 second, and will not being advertising again
    // until the enabler is set back to TRUE
    uint16 gapRole_AdvertOffTime = 0;
      
    //uint8 advType = GAP_ADTYPE_ADV_NONCONN_IND;   // use non-connectable advertisements
    uint8 advType = GAP_ADTYPE_ADV_SCAN_IND; // use scannable unidirected advertisements

    // Set the GAP Role Parameters
    GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &initial_advertising_enable );
    GAPRole_SetParameter( GAPROLE_ADVERT_OFF_TIME, sizeof( uint16 ), &gapRole_AdvertOffTime );
    
    GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, sizeof ( scanRspData ), scanRspData );
    GAPRole_SetParameter( GAPROLE_ADVERT_DATA, sizeof( advertData ), advertData );

    GAPRole_SetParameter( GAPROLE_ADV_EVENT_TYPE, sizeof( uint8 ), &advType );
  }

  // Set advertising interval
  {
    uint16 advInt = DEFAULT_ADVERTISING_INTERVAL;

    GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, advInt );
    GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, advInt );
    GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MIN, advInt );
    GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MAX, advInt );
  }
  
#if defined( CC2540_MINIDK )
 
  // Register for all key events - This app will handle all key events
  RegisterForKeys( simpleBLEBroadcaster_TaskID );
  
  // makes sure LEDs are off
  HalLedSet( (HAL_LED_1 | HAL_LED_2), HAL_LED_MODE_OFF );
  
  // For keyfob board set GPIO pins into a power-optimized state
  // Note that there is still some leakage current from the buzzer,
  // accelerometer, LEDs, and buttons on the PCB.
  
  /*P0SEL = 0; // Configure Port 0 as GPIO
  P1SEL = 0; // Configure Port 1 as GPIO
  P2SEL = 0; // Configure Port 2 as GPIO

  P0DIR = 0xF0; // Port 0 pins P0.0 and P0.1 as input (buttons),
                // all others (P0.2-P0.7) as output
  P1DIR = 0xFF; // All port 1 pins (P1.0-P1.7) as output
  P2DIR = 0x1F; // All port 1 pins (P2.0-P2.4) as output
  
  P0 = 0x00; // All pins on port 0 to low except for P0.0 and P0.1 (buttons)
  P1 = 0;   // All pins on port 1 to low
  P2 = 0;   // All pins on port 2 to low  */
  
#endif // #if defined( CC2540_MINIDK )

#if (defined HAL_LCD) && (HAL_LCD == TRUE)  

  HalLcdWriteString( "BLE Broadcaster", HAL_LCD_LINE_1 );
  
#endif // (defined HAL_LCD) && (HAL_LCD == TRUE)  
  
  // Setup a delayed profile startup
  osal_set_event( simpleBLEBroadcaster_TaskID, SBP_START_DEVICE_EVT );
  /*        #ifdef DEBUG_UART
          deg_msg=(deg_msg_t*)osal_msg_allocate(sizeof(deg_msg_t));
          if(deg_msg)
          {
          deg_msg->hdr.event=DEBUG_MSG;  
          deg_msg->type = uartdeg_app;
          memcpy(deg_msg->msg,"STARTED",7);
          deg_msg->len=7;
          if(serialInterface_TaskID !=0)
            osal_msg_send ( serialInterface_TaskID, (uint8 *) deg_msg );
          }
          #endif */ 
}

/*********************************************************************
 * @fn      SimpleBLEBroadcaster_ProcessEvent
 *
 * @brief   Simple BLE Broadcaster 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  events not processed
 */
uint16 SimpleBLEBroadcaster_ProcessEvent( uint8 task_id, uint16 events )
{
  
  VOID task_id; // OSAL required parameter that isn't used in this function
  
  if ( events & SYS_EVENT_MSG )
  {
    uint8 *pMsg;

    if ( (pMsg = osal_msg_receive( simpleBLEBroadcaster_TaskID )) != NULL )
    {
      simpleBLEBroadcaster_ProcessOSALMsg( (osal_event_hdr_t *)pMsg );

      // Release the OSAL message
      VOID osal_msg_deallocate( pMsg );
    }

    // return unprocessed events
    return (events ^ SYS_EVENT_MSG);
  }

  if ( events & SBP_START_DEVICE_EVT )
  {
    // Start the Device
    VOID GAPRole_StartDevice( &simpleBLEBroadcaster_BroadcasterCBs );
    
    return ( events ^ SBP_START_DEVICE_EVT );
  }
  
  // Discard unknown events
  return 0;
}

/*********************************************************************
 * @fn      simpleBLEBroadcaster_ProcessOSALMsg
 *
 * @brief   Process an incoming task message.
 *
 * @param   pMsg - message to process
 *
 * @return  none
 */
static void simpleBLEBroadcaster_ProcessOSALMsg( osal_event_hdr_t *pMsg )
{
  switch ( pMsg->event )
  {
  #if defined( CC2540_MINIDK )
    case KEY_CHANGE:
      simpleBLEBroadcaster_HandleKeys( ((keyChange_t *)pMsg)->state, ((keyChange_t *)pMsg)->keys );
      break;
  #endif // CC2540_MINIDK
      
  default:
    // do nothing
    break;
  }
}

#if defined( CC2540_MINIDK )
/*********************************************************************
 * @fn      simpleBLEBroadcaster_HandleKeys
 *
 * @brief   Handles all key events for this device.
 *
 * @param   shift - true if in shift/alt.
 * @param   keys - bit field for key events. Valid entries:
 *                 HAL_KEY_SW_2
 *                 HAL_KEY_SW_1
 *
 * @return  none
 */
static void simpleBLEBroadcaster_HandleKeys( uint8 shift, uint8 keys )
{
  VOID shift;  // Intentionally unreferenced parameter

  if ( keys & HAL_KEY_SW_1 )
  {
    advertData[6]++;
    
    GAPRole_SetParameter( GAPROLE_ADVERT_DATA, sizeof( advertData ), advertData );
  }
  
  if ( keys & HAL_KEY_SW_2 )
  {
    // ressing the right key should toggle advertising on and off
    uint8 current_adv_enabled_status;
    uint8 new_adv_enabled_status;
    
    //Find the current GAP advertisement status
    GAPRole_GetParameter( GAPROLE_ADVERT_ENABLED, &current_adv_enabled_status );
    
    if( current_adv_enabled_status == FALSE )
    {
      new_adv_enabled_status = TRUE;
    }
    else
    {
      new_adv_enabled_status = FALSE;
    }
    
    //change the GAP advertisement status to opposite of current status
    GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &new_adv_enabled_status );
  }
}
#endif // CC2540_MINIDK

/*********************************************************************
 * @fn      peripheralStateNotificationCB
 *
 * @brief   Notification from the profile of a state change.
 *
 * @param   newState - new state
 *
 * @return  none
 */
static void peripheralStateNotificationCB( gaprole_States_t newState )
{
  switch ( newState )
  {
    case GAPROLE_STARTED:
      {    
        uint8 ownAddress[B_ADDR_LEN];
        
        GAPRole_GetParameter(GAPROLE_BD_ADDR, ownAddress);
    
        #if (defined HAL_LCD) && (HAL_LCD == TRUE)
          // Display device address 
          HalLcdWriteString( bdAddr2Str( ownAddress ),  HAL_LCD_LINE_2 );
          HalLcdWriteString( "Initialized",  HAL_LCD_LINE_3 );
        #endif // (defined HAL_LCD) && (HAL_LCD == TRUE)    
      }
      break;
      
    case GAPROLE_ADVERTISING:
      {
        HalLedSet( (HAL_LED_1 | HAL_LED_2), HAL_LED_MODE_ON );
        #if (defined HAL_LCD) && (HAL_LCD == TRUE)
          HalLcdWriteString( "Advertising",  HAL_LCD_LINE_3 );
        #endif // (defined HAL_LCD) && (HAL_LCD == TRUE)            
      }
      break;

    case GAPROLE_WAITING:
      {
        #if (defined HAL_LCD) && (HAL_LCD == TRUE)
          HalLcdWriteString( "Waiting",  HAL_LCD_LINE_3 );
        #endif // (defined HAL_LCD) && (HAL_LCD == TRUE)            
      }
      break;          

    case GAPROLE_ERROR:
      {
        #if (defined HAL_LCD) && (HAL_LCD == TRUE)
          HalLcdWriteString( "Error",  HAL_LCD_LINE_3 );
        #endif // (defined HAL_LCD) && (HAL_LCD == TRUE)            
      }
      break;      
      
    default:
      {
        #if (defined HAL_LCD) && (HAL_LCD == TRUE)
          HalLcdWriteString( "",  HAL_LCD_LINE_3 );
        #endif // (defined HAL_LCD) && (HAL_LCD == TRUE)     
      }        
      break; 
  }
}

//to start adv
uint8 Application_StartAdvertise(void)
{
        uint8 astatus;

        // toggle GAP advertisement status
        GAPRole_GetParameter( GAPROLE_ADVERT_ENABLED, &astatus );
        if (astatus == FALSE)
        {
            //Set fast advertising interval for user-initiated connections
            /*GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, interval );
            GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, interval );
            GAP_SetParamValue( TGAP_LIM_ADV_TIMEOUT, duration );*/
            astatus = TRUE;
            GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &astatus );
            return TRUE;
        }
        else
            return FALSE;
}

//to stop adv
uint8 Application_StopAdvertise(void)
{
        uint8 astatus;

        // toggle GAP advertisement status
        GAPRole_GetParameter( GAPROLE_ADVERT_ENABLED, &astatus );
        if (astatus == TRUE)
        {
            astatus = FALSE;
            GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &astatus );
            return TRUE;
        }
        else
            return FALSE;
}

//to updata the adv
//21 Bytes,6 bytes MIC,10 Bytes pw(max),2 bytes reserve,1 byte wifi security and 1 byte ,tx power
uint8 Application_UpdateAdv(int len,uint8 *adv)
{
        memcpy(advertData,adv,len);
        //should be disable ble
        VOID osal_snv_write( BLE_NVID_ADV, sizeof( advertData ), &advertData );     
        GAPRole_SetParameter( GAPROLE_ADVERT_DATA, sizeof( advertData ), advertData );
        return TRUE;
}

//to update the response
uint8 Application_UpdateRsp(int len,uint8 *rsp)
{
        memset(scanRspData,0x00,sizeof(scanRspData));
        scanRspData[RSPLEN]=len;
        scanRspData[RSPPRO]=RSPDEVNAME;
        memcpy(scanRspData,rsp,len);
        VOID osal_snv_write( BLE_NVID_RSP, sizeof( scanRspData ), &scanRspData );    
        GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, sizeof ( scanRspData ), scanRspData );
        return TRUE;
}

/*********************************************************************
*********************************************************************/
