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

@file  app_data.c

@brief This file contains the application data functionality

Group: WCS, BTS
Target Device: cc23xx

******************************************************************************

 Copyright (c) 2022-2025, Texas Instruments Incorporated
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:

 *  Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

 *  Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

 *  Neither the name of Texas Instruments Incorporated nor the names of
    its contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

******************************************************************************


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

//*****************************************************************************
//! Includes
//*****************************************************************************
#include <string.h>
#include "ti/ble/app_util/framework/bleapputil_api.h"
#include "ti/ble/app_util/menu/menu_module.h"
#include <app_main.h>
#include "FreeRTOS.h"
#include "timers.h"

//*****************************************************************************
//! Defines
//*****************************************************************************
extern uint8_t gStartCentralMode;
void AddDebuggingflowState(uint8_t state);
//*****************************************************************************
//! Globals
//*****************************************************************************
//#define BLE_CENTRAL_CMD_TIMEOUT
#ifdef BLE_CENTRAL_CMD_TIMEOUT
uint8_t benablecentraltimer = false;
uint8_t bcentraltimercreaterd = false;
TimerHandle_t centraltimerhandle ;
extern void myCentralRspTimeoutToRXCallback(TimerHandle_t xTimer);
#endif

#define BACKUP_CMD_OFFSET (1024)
#define CENTRAL_CONNECT_INTERVAL 48
static void GATT_EventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData);
#define DEBUG_RESPONSE_BUF_SIZE 24
extern uint8_t DebugFFRespnoseBackup[DEBUG_RESPONSE_BUF_SIZE];
// Events handlers struct, contains the handlers and event masks
// of the application data module
BLEAppUtil_EventHandler_t dataGATTHandler =
{
    .handlerType    = BLEAPPUTIL_GATT_TYPE,
    .pEventHandler  = GATT_EventHandler,
    .eventMask      = BLEAPPUTIL_ATT_FLOW_CTRL_VIOLATED_EVENT |
                      BLEAPPUTIL_ATT_MTU_UPDATED_EVENT |
                      BLEAPPUTIL_ATT_FIND_BY_TYPE_VALUE_RSP | 
                      BLEAPPUTIL_ATT_READ_BY_TYPE_RSP |
                      BLEAPPUTIL_ATT_READ_BY_GRP_TYPE_RSP |
                      BLEAPPUTIL_ATT_READ_RSP |
                      BLEAPPUTIL_ATT_HANDLE_VALUE_NOTI |
                      BLEAPPUTIL_ATT_FIND_INFO_RSP
};

extern uint8_t InstaxDataInUUID[ATT_UUID_SIZE]; 
extern uint8_t InstaxDataOutUUID[ATT_UUID_SIZE];
 uint16_t attManuFHandle =0;
 uint16_t attDataInHandle =0;
 uint16_t attDataOutHandle =0;
 #define SPI_MSG_LENGTH 2048
 extern unsigned char peripheralTxBuffer[SPI_MSG_LENGTH]; 
 extern unsigned char bleRxBuffer[SPI_MSG_LENGTH];
 extern uint16_t bleTxBufferlen;
 extern uint8_t NotifyTPResponse();
 uint8_t downloadcount =0;
//*****************************************************************************
//! Functions
//*****************************************************************************
/* Characteristics */
#define DIS_MANUFACTURER_UUID     0x2A29
#define DIS_MODEL_NUMBER_UUID     0x2A24
#define DIS_FIRMWARE_UUID         0x2A26
/*********************************************************************
 * @fn      GATT_EventHandler
 *
 * @brief   The purpose of this function is to handle GATT events
 *          that rise from the GATT and were registered in
 *          @ref BLEAppUtil_RegisterGAPEvent
 *
 * @param   event - message event.
 * @param   pMsgData - pointer to message data.
 *
 * @return  none
 */

//extern uint16_t attManuFHandle;
void Menu_ReadManuFactoryNameCB(char *pData)
{
    bStatus_t status;
    uint16_t connHandle;
    attReadReq_t req;

    connHandle =  Connection_getConnhandle(0); // InstaxDataInUUID      
    req.handle = attManuFHandle;
    status = GATT_ReadCharValue(connHandle, &req,
                           BLEAppUtil_getSelfEntity());
}

extern void Menu_doGattWriteCB(char *pData);
#define SHORTBLERESPONSESIZE 48
//extern unsigned char shortbleresponsebuf[SHORTBLERESPONSESIZE];
uint8_t tmp_readdevicename = 0;
static void GATT_EventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData)
{
  gattMsgEvent_t *gattMsg = ( gattMsgEvent_t * )pMsgData;
  switch ( gattMsg->method )
  {
    case ATT_FIND_BY_TYPE_VALUE_RSP:
    {
        uint16_t lastStart;
        uint16_t lastEnd;
        uint16_t display_index =0;
        attFindByTypeValueRsp_t att = (attFindByTypeValueRsp_t)gattMsg->msg.findByTypeValueRsp;
        
        /* We need to build the 16-bit handles that we received when we discovered the service. */
        for (uint8_t i = 0; i < att.numInfo; i++)
        {
            /* NOTE: We are in little endian, but the BUILD_UINT16 macro accounts for this */

            /* The first two bytes will be start handle */
            uint16_t attHandle = BUILD_UINT16(att.pHandlesInfo[i * 4], att.pHandlesInfo[i * 4 + 1]);
            /* The second two bytes will be the end handle */
            uint16_t endHandle = BUILD_UINT16(att.pHandlesInfo[i * 4 + 2], att.pHandlesInfo[i * 4 + 3]);
            
            lastStart = attHandle;
            lastEnd = endHandle;

            MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE + display_index, 0, "start: %x", attHandle);
            display_index++;
            MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE + display_index, 0, "end: %x", endHandle);
            display_index++;
        }

        /* This delay can be replaced with a timer, or applicaton event that then calls GATT_DiscAllChars.
         * Without a delay, timer, or separate application event, this call will fail since the stack is busy
         * processing messages during this time. For the sake of the example, a delay was used, but
         * it does not have to be an explicit delay.
         */

       // ClockP_sleep(1);
        uint8_t retry = 0;
        while(retry < 10)
        {
          ClockP_usleep(200*1000); //100 ms
          bStatus_t bstatus = GATT_DiscAllChars(gattMsg->connHandle,
                                                lastStart,
                                                lastEnd,
                                                BLEAppUtil_getSelfEntity());
          if (bstatus != SUCCESS)
          {
              MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE + display_index, 0,"FAILED!!!");
              display_index++;
              retry++;
          }
          else 
              retry = 10;          
        }
  
    }
    break;
    case ATT_READ_BY_GRP_TYPE_RSP:
    {     
      uint16_t display_index =0;
      uint16_t lastStart;
      uint16_t lastEnd;
      attReadByGrpTypeRsp_t att = (attReadByGrpTypeRsp_t)gattMsg->msg.readByGrpTypeRsp;     
      for (uint8_t i = 0; i < att.numGrps; i++)
      {
        
      }
    }
    break;
    case ATT_READ_BY_TYPE_RSP:
    {
        uint16_t display_index =0;
        bStatus_t bstatus;
        uint16_t startHandle =0;
        uint16_t endHandle1 = 0;

        attReadByTypeRsp_t att = (attReadByTypeRsp_t)gattMsg->msg.readByTypeRsp;

        if (att.numPairs == 0)
            break;

        MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE + display_index, 0, "ATT_READ_BY_TYPE_RSP");
        display_index++;
        MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE + display_index, 0, "Length: %d : Number of Pairs: %d", att.len, att.numPairs);
        display_index++;
        
  


        for (uint8_t i = 0; i < att.numPairs; i++)
        {
            /* This is the Attribute Handle */
            uint16_t attHandle = BUILD_UINT16(att.pDataList[i * att.len + 0], att.pDataList[i * att.len + 1]);

            /* This is the index to the beginning of the value data AFTER the attribute handle */
            uint8_t index = i * att.len + 2;

            /* The characteristic value data */
            uint8_t char_properties = att.pDataList[index];     // Bit field of characteristic properties

            uint16_t value_handle = BUILD_UINT16(att.pDataList[index + 1], att.pDataList[index + 2]);

            MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE + display_index, 0,
                              "    ATT Handle: %x : Value Handle %x : Properties : %x",
                              attHandle, value_handle, char_properties);
            display_index++;
            
            if (tmp_readdevicename == 1) //backup the central name
            {
                tmp_readdevicename = att.len;
                if (tmp_readdevicename > DEBUG_RESPONSE_BUF_SIZE-5) tmp_readdevicename = DEBUG_RESPONSE_BUF_SIZE -5;
                //offset 4 byte after pair code
                memcpy(DebugFFRespnoseBackup+5 , (void*)&(att.pDataList[index]) , tmp_readdevicename);
                //bleTxBufferlen =  att.len;
            }
             uint8_t data2 = att.pDataList[index + 1]; // Second Byte of Characteristic Value Handle
            uint8_t data3 = att.pDataList[index + 2]; // First Byte of Characteristic Value Handle
            if (att.len - 5 == 2)
            {
               attReadReq_t req;
               req.handle = attHandle;
               uint16_t char_16bit_uuid = BUILD_UINT16(att.pDataList[index + 3], att.pDataList[index + 4]);
               MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE + display_index, 0,"    UUID: %x", char_16bit_uuid);
               display_index++;
               switch (char_16bit_uuid)
                {
                  case DIS_MANUFACTURER_UUID:                  
                    //  attManuFHandle = attHandle;
                  //   bstatus = GATT_ReadCharValue(gattMsg->connHandle, &req,
                  //         BLEAppUtil_getSelfEntity());
                   // BLEAppUtil_invokeFunctionNoData(Menu_ReadManuFactoryNameCB);
                    break;
                  case DIS_MODEL_NUMBER_UUID:
                    
                    break;
                  case DIS_FIRMWARE_UUID:
                    attManuFHandle = attHandle;
                    break;
                   case GATT_CLIENT_CHAR_CFG_UUID:
                    attManuFHandle = attHandle;
                    break;
                }              
            }
            else
            {
                MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE + display_index, 0,"    UUID: ");
                uint8_t bfound = true;
                for (uint8_t j = 0; j < 16; j++)
                {
                  if (InstaxDataOutUUID[j] != att.pDataList[index + 3 + j])
                  {                     
                    bfound = false; break;
                  }                  
                }
                if (bfound)  
                {                  
                    attDataOutHandle = BUILD_UINT16(data2, data3); 
  endHandle1 = BUILD_UINT16(data2, data3); 
                }
                                
                bfound = true;
                for (uint8_t j = 0; j < 16; j++)
                {
                  if (InstaxDataInUUID[j] != att.pDataList[index + 3 + j])
                  {                     
                    bfound = false; break;
                  }                  
                }
                if (bfound) 
                {
                    attDataInHandle = BUILD_UINT16(data2, data3);                      
                    startHandle = BUILD_UINT16(data2, data3);    
                }
                MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE + display_index, j + 10, "%x", att.pDataList[index + 3 + j]);                                
                //NotifyBLEConnectStatus(3);  // debug
                display_index++;
            }
        }

        // Call the GATT_DiscAllCharDesc()
        if (att.numPairs > 0)
        {
          uint8_t retry = 0;
          
          // ClockP_sleep(1);
          while (retry < 10)
          {
            ClockP_usleep(200 *1000); 
            bstatus = GATT_DiscAllCharDescs(gattMsg->connHandle, endHandle1+1 , endHandle1+10 , BLEAppUtil_getSelfEntity());
            if (bstatus != SUCCESS )
            {
              bstatus = 0;
              retry++;
            }
            else retry = 10;
          }  
        }
    }
    break;
    case ATT_FIND_INFO_RSP:
    {
      attFindInfoRsp_t rsp = (attFindInfoRsp_t)gattMsg->msg.findInfoRsp;
      MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE + display_index++, 0,"Event ATT_FIND_INFO_RSP Recieved");

        for (uint8_t i = 0; i < rsp.numInfo; i++)
        {
            /* This is the Attribute Handle */
            // uint16_t attHandle = BUILD_UINT16(att.pDataList[i * att.len + 0], att.pDataList[i * att.len + 1]);
            uint16_t attHandle = BUILD_UINT16(rsp.pInfo[0], rsp.pInfo[1]);

            MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE + display_index++, 0,"ATT Handle: %x", attHandle);
        

            /* This is the index to the beginning of the value data AFTER the attribute handle */
            uint8_t index = i * rsp.numInfo + 2;

            /* The characteristic value data */
            uint8_t data1 = rsp.pInfo[index];     // UUID LSB
            uint8_t data2 = rsp.pInfo[index + 1]; // UUID MSB
            
            uint16_t UUID = BUILD_UINT16(data1,  data2);

            
          if(UUID==0x2902){
            MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE + display_index++, 0,"CCCD Discovered");

            // Write to the CCCD
          //  ClockP_sleep(1);
         // ClockP_usleep(500000); //500 ms
            uint8_t retry = 0;
            while (retry < 4)
            {
              ClockP_usleep(500*1000);                 

              uint8_t val[2] = {0x01, 0x00};
              attWriteReq_t writeReq;

              writeReq.cmd = 0;
              writeReq.handle = attHandle;
              writeReq.len = 2;
              writeReq.sig = 0;
      //        connn = gattMsg->connHandle;
              
              writeReq.pValue = GATT_bm_alloc(gattMsg->connHandle, ATT_WRITE_REQ, writeReq.len, NULL);
              if (writeReq.pValue) {
                writeReq.pValue[0] = 0x01;   // notifications = 0x0001 (little-endian)
                writeReq.pValue[1] = 0x00;
                
                bStatus_t s = GATT_WriteCharValue(gattMsg->connHandle, &writeReq, BLEAppUtil_getSelfEntity());
                if (s != SUCCESS) {
                  GATT_bm_free((gattMsg_t *)&writeReq, ATT_WRITE_REQ);
                  retry++;
                }
                else retry = 10;
              }
              else  retry++;
            }

              
                bStatus_t status;
                gapUpdateLinkParamReq_t pParamUpdateReq =
                {
                .connectionHandle = gattMsg->connHandle,
                .intervalMin = CENTRAL_CONNECT_INTERVAL,
                .intervalMax = CENTRAL_CONNECT_INTERVAL,
                .connLatency = 0,
                .connTimeout = 400,
                };                
                downloadcount = 0;
              
                // Send a connection param update request
                status = BLEAppUtil_paramUpdateReq(&pParamUpdateReq);
              //  ClockP_usleep(100*1000);
               // Menu_doGattWriteCB(NULL);
               // 
                if (gStartCentralMode)   
                { 
              //    BLEAppUtil_invokeFunction(Menu_doGattWriteCB , NULL);
             //    ClockP_usleep(500*1000);
                  NotifyBLEConnectStatus(3);  
                }
               
              // if (SUCCESS != status)
              //    status =0; //debug
              
            }                             
        }
    }
    break;
    case ATT_FLOW_CTRL_VIOLATED_EVENT:
      {
          MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE, 0, "GATT status: ATT flow control is violated");
      }
      break;

    case ATT_MTU_UPDATED_EVENT:
      {
          MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE, 0, "GATT status: ATT MTU update to %d",
                            gattMsg->msg.mtuEvt.MTU);
          //GAPBondMgr_Pair(Connection_getConnhandle(0));     
          if (!gStartCentralMode) 
          {
          uint8_t retry = 0;
          while (retry < 10) 
          {
            ClockP_usleep(100*1000);
                          attReadByTypeReq_t req;
          req.startHandle = 0x0001;
          req.endHandle = 0xFFFF;
          req.type.len = ATT_BT_UUID_SIZE;
          req.type.uuid[0] = LO_UINT16(DEVICE_NAME_UUID);
          req.type.uuid[1] = HI_UINT16(DEVICE_NAME_UUID);
          bStatus_t  status = GATT_ReadUsingCharUUID(Connection_getConnhandle(0), &req ,  BLEAppUtil_getSelfEntity());
          if (status != SUCCESS) 
          {
                  retry++;
          }  
            else  
            {    
              retry = 10;
              tmp_readdevicename =1;
            }
          } 
          }
          else {

#ifdef BLE_CENTRAL_CMD_TIMEOUT                        
                          if (bcentraltimercreaterd == false)
                          {
                          centraltimerhandle =  xTimerCreate("MyTimer",
                           pdMS_TO_TICKS(1000),   // period in ms
                           pdTRUE,                // auto-reload
                           (void *)0,
                           myCentralRspTimeoutToRXCallback);
                           bcentraltimercreaterd = true;
                           if (centraltimerhandle != NULL) {
                            xTimerStart(centraltimerhandle, 0);    
                            }
                          }
  #endif
          }  
        //   GATT_UpdateMTU(Connection_getConnhandle(0) , 247);
      }
      break;
     case  ATT_READ_RSP:
     {
      //    uint16_t handle = gattMsg->msg.readRsp.handle;
          uint8_t *data   = gattMsg->msg.readRsp.pValue;
          uint8_t len     = gattMsg->msg.readRsp.len;

     }
     break;

     case ATT_HANDLE_VALUE_NOTI:
     {
        uint8_t len     = gattMsg->msg.readRsp.len;
        uint8_t *data   = gattMsg->msg.readRsp.pValue;
        uint8_t length = 16;
        
#ifdef BLE_CENTRAL_CMD_TIMEOUT       
      //  xTimerStop(centraltimerhandle , 0);  // disable timeout
      benablecentraltimer = false;
 #endif
        AddDebuggingflowState(138);
      //  memcpy(&peripheralTxBuffer[4] ,  data , len);
       // if (data[4] ==0x10 && data[5] ==0x01)
        { 
           downloadcount++;           
        }        
        if (len < 16) 
           length = len;       
        if (tmp_readdevicename == 0)
            memcpy(DebugFFRespnoseBackup ,  data , length); 

        memcpy(&bleRxBuffer[BACKUP_CMD_OFFSET] ,  data , len);   
        bleTxBufferlen = len;
        NotifyTPResponse(); 
     }
     break;

    default:
      break;
  }
}

/*********************************************************************
 * @fn      Data_start
 *
 * @brief   This function is called after stack initialization,
 *          the purpose of this function is to initialize and
 *          register the specific events handlers of the data
 *          application module
 *
 * @return  SUCCESS, errorInfo
 */
bStatus_t Data_start( void )
{
  bStatus_t status = SUCCESS;

  // Register the handlers
  status = BLEAppUtil_registerEventHandler( &dataGATTHandler );

  // Return status value
  return( status );
}


/*********************************************************************
 * @fn      SimpleBLECentral_EnableNotification
 *
 * @brief   Enable notification for a given attribute handle.
 *
 * @param   connHandle - connection handle to send notification on
 * @param   attrHandle - attribute handle to send notification for
 *
 * @return  none
 */
static void SimpleBLECentral_EnableNotification( uint16 connHandle, uint16 attrHandle )
{
  attWriteReq_t req;

  req.pValue = GATT_bm_alloc( connHandle, ATT_WRITE_REQ, 2, NULL );
  if ( req.pValue != NULL )
  {
    uint8 notificationsOn[] = {0x01, 0x00};
    req.handle = attrHandle;

    req.len = 2;
    memcpy(req.pValue, notificationsOn, 2);

    req.sig = FALSE;
    req.cmd = TRUE;

    if ( GATT_WriteNoRsp( connHandle, &req ) != SUCCESS )
    {
      GATT_bm_free( (gattMsg_t *)&req, ATT_WRITE_REQ );
    }

  }
}
