/**************************************************************************************************
  Filename:       ppsp_serv.c
  Revised:
  Revision:

  Description:    This file contains the Simple GATT profile sample GATT service
                  profile for use with the BLE sample application.


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

/*********************************************************************
 * INCLUDES
 */
#include "bcomdef.h"
#include "OSAL.h"
#include "linkdb.h"
#include "att.h"
#include "gatt.h"
#include "gatt_uuid.h"
#include "gattservapp.h"
#include "gapbondmgr.h"

#include "ppsp_serv.h"

#include "log.h"


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

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

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

/*********************************************************************
 * GLOBAL VARIABLES
 */
// Simple GATT Profile Service UUID: 0xFFF0
CONST uint8 __ppsp_serv_serv_uuid[ATT_BT_UUID_SIZE] = {
  LO_UINT16(PPSP_SERV_CFGS_SERV_FEB3_UUID), HI_UINT16(PPSP_SERV_CFGS_SERV_FEB3_UUID)
};

// Characteristic 1 UUID: 0xFFF1
CONST uint8 __ppsp_serv_char_ffd4_uuid[ATT_BT_UUID_SIZE] = {
  LO_UINT16(PPSP_SERV_CFGS_CHAR_FED4_UUID), HI_UINT16(PPSP_SERV_CFGS_CHAR_FED4_UUID)
};

// Characteristic 2 UUID: 0xFFF2
CONST uint8 __ppsp_serv_char_ffd5_uuid[ATT_BT_UUID_SIZE] = {
  LO_UINT16(PPSP_SERV_CFGS_CHAR_FED5_UUID), HI_UINT16(PPSP_SERV_CFGS_CHAR_FED5_UUID)
};

// Characteristic 3 UUID: 0xFFF3
CONST uint8 __ppsp_serv_char_ffd6_uuid[ATT_BT_UUID_SIZE] = {
  LO_UINT16(PPSP_SERV_CFGS_CHAR_FED6_UUID), HI_UINT16(PPSP_SERV_CFGS_CHAR_FED6_UUID)
};

// Characteristic 4 UUID: 0xFFF4
CONST uint8 __ppsp_serv_char_ffd7_uuid[ATT_BT_UUID_SIZE] = {
  LO_UINT16(PPSP_SERV_CFGS_CHAR_FED7_UUID), HI_UINT16(PPSP_SERV_CFGS_CHAR_FED7_UUID)
};

// Characteristic 5 UUID: 0xFFF5
CONST uint8 __ppsp_serv_char_ffd8_uuid[ATT_BT_UUID_SIZE] = {
  LO_UINT16(PPSP_SERV_CFGS_CHAR_FED8_UUID), HI_UINT16(PPSP_SERV_CFGS_CHAR_FED8_UUID)
};


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

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

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

static ppsp_serv_appl_CBs_t *simpleProfile_AppCBs = NULL;

/*********************************************************************
 * Profile Attributes - variables
 */

// Simple Profile Service attribute
static CONST gattAttrType_t
__ppsp_serv_serv = { ATT_BT_UUID_SIZE, __ppsp_serv_serv_uuid };


// Simple Profile Characteristic 1 Properties
static uint8
__ppsp_serv_char_ffd4_prop = GATT_PROP_READ;

// Characteristic 1 Value
static uint8
__ppsp_serv_char_ffd4_para[PPSP_SERV_CFGS_CHAR_FED4_DLEN];
static uint8
__ppsp_serv_char_ffd4_para_size = 0;
// Simple Profile Characteristic 1 User Description
static uint8
__ppsp_serv_char_ffd4_desc[] = "READ\0";


// Simple Profile Characteristic 2 Properties
static uint8
__ppsp_serv_char_ffd5_prop = GATT_PROP_WRITE;

// Characteristic 2 Value
static uint8
__ppsp_serv_char_ffd5_para[PPSP_SERV_CFGS_CHAR_FED5_DLEN];

// Simple Profile Characteristic 2 User Description
static uint8
__ppsp_serv_char_ffd5_desc[] = "WRITE\0";


// Simple Profile Characteristic 3 Properties
static uint8
__ppsp_serv_char_ffd6_prop = GATT_PROP_READ | GATT_PROP_INDICATE;

// Characteristic 3 Value
static uint8
__ppsp_serv_char_ffd6_para[PPSP_SERV_CFGS_CHAR_FED6_DLEN];
static uint8
__ppsp_serv_char_ffd6_para_size = 0;
// Simple Profile Characteristic 4 Configuration Each client has its own
// instantiation of the Client Characteristic Configuration. Reads of the
// Client Characteristic Configuration only shows the configuration for
// that client and writes only affect the configuration of that client.
static gattCharCfg_t
__ppsp_serv_char_ffd6_cfgs[GATT_MAX_NUM_CONN];

// Simple Profile Characteristic 3 User Description
static uint8
__ppsp_serv_char_ffd6_desc[] = "INDICATE\0";


// Simple Profile Characteristic 4 Properties
static uint8
__ppsp_serv_char_ffd7_prop = GATT_PROP_WRITE_NO_RSP;

// Characteristic 4 Value
static uint8
__ppsp_serv_char_ffd7_para[PPSP_SERV_CFGS_CHAR_FED7_DLEN];

// Simple Profile Characteristic 4 User Description
static uint8
__ppsp_serv_char_ffd7_desc[] = "WRITE_WITH_NO_RESP\0";


// Simple Profile Characteristic 5 Properties
static uint8
__ppsp_serv_char_ffd8_prop = GATT_PROP_READ | GATT_PROP_NOTIFY;   // to change to write only, HZF

// Characteristic 5 Value
static uint8
__ppsp_serv_char_ffd8_para[PPSP_SERV_CFGS_CHAR_FED8_DLEN];
static uint8
__ppsp_serv_char_ffd8_para_size = 0;
// Simple Profile Characteristic 1 Configuration Each client has its own
// instantiation of the Client Characteristic Configuration. Reads of the
// Client Characteristic Configuration only shows the configuration for
// that client and writes only affect the configuration of that client.
static gattCharCfg_t __ppsp_serv_char_ffd8_cfgs[GATT_MAX_NUM_CONN];

// Simple Profile Characteristic 5 User Description
static uint8
__ppsp_serv_char_ffd8_desc[] = "NOTIFY\0";



/*********************************************************************
 * Profile Attributes - Table
 */

static gattAttribute_t simpleProfileAttrTbl[] =
{
  // Simple Profile Service
  {
    { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */
    GATT_PERMIT_READ,                         /* permissions */
    0,                                        /* handle */
    (uint8 *)&__ppsp_serv_serv                /* pValue */
  },

    // Characteristic 1 Declaration
    {
      { ATT_BT_UUID_SIZE, characterUUID },
      GATT_PERMIT_READ,
      0,
      &__ppsp_serv_char_ffd4_prop
    },
      // Characteristic Value 1
      {
        { ATT_BT_UUID_SIZE, __ppsp_serv_char_ffd4_uuid },
        GATT_PERMIT_READ | GATT_PERMIT_WRITE,
        0,
        __ppsp_serv_char_ffd4_para
      },
      // Characteristic 1 User Description
      /* {
        { ATT_BT_UUID_SIZE, charUserDescUUID },
        GATT_PERMIT_READ,
        0,
        __ppsp_serv_char_FFD4_desc
      }, */

    // Characteristic 2 Declaration
    {
      { ATT_BT_UUID_SIZE, characterUUID },
      GATT_PERMIT_READ,
      0,
      &__ppsp_serv_char_ffd5_prop
    },
      // Characteristic Value 2
      {
        { ATT_BT_UUID_SIZE, __ppsp_serv_char_ffd5_uuid },
        GATT_PERMIT_READ | GATT_PERMIT_WRITE,
        0,
        __ppsp_serv_char_ffd5_para
      },
      // Characteristic 2 User Description
      /* {
        { ATT_BT_UUID_SIZE, charUserDescUUID },
        GATT_PERMIT_READ,
        0,
        __ppsp_serv_char_FFD5_desc
      }, */

    // Characteristic 3 Declaration
    {
      { ATT_BT_UUID_SIZE, characterUUID },
      GATT_PERMIT_READ,
      0,
      &__ppsp_serv_char_ffd6_prop
    },
      // Characteristic Value 3
      {
        { ATT_BT_UUID_SIZE, __ppsp_serv_char_ffd6_uuid },
        GATT_PERMIT_READ | GATT_PERMIT_WRITE,
        0,
        __ppsp_serv_char_ffd6_para
      },
      // Characteristic 3 configuration
      {
        { ATT_BT_UUID_SIZE, clientCharCfgUUID },
        GATT_PERMIT_READ | GATT_PERMIT_WRITE,
        0,
        (uint8 *)__ppsp_serv_char_ffd6_cfgs
      },
      // Characteristic 3 User Description
      /* {
        { ATT_BT_UUID_SIZE, charUserDescUUID },
        GATT_PERMIT_READ,
        0,
        __ppsp_serv_char_FFD6_desc
      }, */

    // Characteristic 4 Declaration
    {
      { ATT_BT_UUID_SIZE, characterUUID },
      GATT_PERMIT_READ,
      0,
      &__ppsp_serv_char_ffd7_prop
    },
      // Characteristic Value 4
      {
        { ATT_BT_UUID_SIZE, __ppsp_serv_char_ffd7_uuid },
        GATT_PERMIT_READ | GATT_PERMIT_WRITE,
        0,
        __ppsp_serv_char_ffd7_para
      },
      // Characteristic 4 User Description
      /* {
        { ATT_BT_UUID_SIZE, charUserDescUUID },
        GATT_PERMIT_READ,
        0,
        __ppsp_serv_char_FFD7_desc
      }, */

    // Characteristic 5 Declaration
    {
      { ATT_BT_UUID_SIZE, characterUUID },
      GATT_PERMIT_READ,
      0,
      &__ppsp_serv_char_ffd8_prop
    },
      // Characteristic Value 5
      {
        { ATT_BT_UUID_SIZE, __ppsp_serv_char_ffd8_uuid },
        GATT_PERMIT_READ | GATT_PERMIT_WRITE,
        0,
        __ppsp_serv_char_ffd8_para
      },
      // Characteristic 5 configuration
      {
        { ATT_BT_UUID_SIZE, clientCharCfgUUID },
        GATT_PERMIT_READ | GATT_PERMIT_WRITE,
        0,
        (uint8 *)__ppsp_serv_char_ffd8_cfgs
      },
      // Characteristic 5 User Description
      /* {
        { ATT_BT_UUID_SIZE, charUserDescUUID },
        GATT_PERMIT_READ,
        0,
        __ppsp_serv_char_FFD8_desc
      }, */
};


/*********************************************************************
 * LOCAL FUNCTIONS
 */
static uint8
ppsp_serv_get_attr( uint16 connHandle, gattAttribute_t *pAttr,
                    uint8 *pValue, uint8 *pLen, uint16 offset, uint8 maxLen );
static bStatus_t
ppsp_serv_set_attr( uint16 connHandle, gattAttribute_t *pAttr,
                    uint8 *pValue, uint8 len, uint16 offset );
static void
ppsp_serv_hdlr_conn_stat( uint16 connHandle, uint8 changeType );

// static bStatus_t send_notity_indication( gattCharCfg_t *charCfgTbl, uint8 *pValue,
//                                       uint8 authenticated, gattAttribute_t *attrTbl,
//                                       uint16 numAttrs, uint8 taskId,uint8 dlen);


/*********************************************************************
 * @fn          simpleProfile_ReadAttrCB
 *
 * @brief       Read an attribute.
 *
 * @param       connHandle - connection message was received on
 * @param       pAttr - pointer to attribute
 * @param       pValue - pointer to data to be read
 * @param       pLen - length of data to be read
 * @param       offset - offset of the first octet to be read
 * @param       maxLen - maximum length of data to be read
 *
 * @return      Success or Failure
 */
static uint8 ppsp_serv_get_attr( uint16 connHandle, gattAttribute_t *pAttr,
                            uint8 *pValue, uint8 *pLen, uint16 offset, uint8 maxLen )
{
  bStatus_t status = SUCCESS;

  // LOG("[PANDA][ENT] %s len:%d, offs:%d, max:%d \r\n", __func__, *pLen, offset, maxLen);
  // printf("[PANDA][INF] mtu:%d", ATT_GetCurrentMTUSize());

  // If attribute permissions require authorization to read, return error
  if ( gattPermitAuthorRead( pAttr->permissions ) ) {
    // Insufficient authorization
    return ( ATT_ERR_INSUFFICIENT_AUTHOR );
  }

  // Make sure it's not a blob operation (no attributes in the profile are long)
  // if ( 0 <  offset ) {
  //   return ( ATT_ERR_ATTR_NOT_LONG );
  // }

  if ( pAttr->type.len == ATT_BT_UUID_SIZE ) {
    // 16-bit UUID
    uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
    // LOG("[PANDA][INF] uuid:%x \r\n", uuid);

    uint16 gsiz = offset + 1; // size of read
    uint16 ssiz = 0;          // size of left
    switch ( uuid ) {
      // No need for "GATT_SERVICE_UUID" or "GATT_CLIENT_CHAR_CFG_UUID" cases;
      // gattserverapp handles those reads

      case PPSP_SERV_CFGS_CHAR_FED4_UUID: {
        ssiz = PPSP_SERV_CFGS_CHAR_FED4_DLEN - gsiz;
	      *pLen = ssiz > maxLen ? maxLen : ssiz;
	      VOID osal_memcpy( pValue, pAttr->pValue + offset, *pLen );
      }
      break;

      case PPSP_SERV_CFGS_CHAR_FED5_UUID: {
        ssiz = PPSP_SERV_CFGS_CHAR_FED5_DLEN - gsiz;
	      *pLen = ssiz > maxLen ? maxLen : ssiz;
	      VOID osal_memcpy( pValue, pAttr->pValue + offset, *pLen );
      }
      break;

        case PPSP_SERV_CFGS_CHAR_FED6_UUID: {
            ssiz = PPSP_SERV_CFGS_CHAR_FED6_DLEN - gsiz;
	          *pLen = ssiz > maxLen ? maxLen : ssiz;
	      //osal_memcpy( pValue, pAttr->pValue + offset, *pLen );
          osal_memcpy( pValue, pAttr->pValue, *pLen = __ppsp_serv_char_ffd6_para_size );

      }
      break;

      case PPSP_SERV_CFGS_CHAR_FED7_UUID: {
        ssiz = PPSP_SERV_CFGS_CHAR_FED7_DLEN - gsiz;
	      *pLen = ssiz > maxLen ? maxLen : ssiz;
	      VOID osal_memcpy( pValue, pAttr->pValue + offset, *pLen );
      }
      break;

      case PPSP_SERV_CFGS_CHAR_FED8_UUID: {
        ssiz = PPSP_SERV_CFGS_CHAR_FED8_DLEN - gsiz;
	      *pLen = ssiz > maxLen ? maxLen : ssiz;
	      // VOID osal_memcpy( pValue, pAttr->pValue + offset, *pLen );
        osal_memcpy( pValue, pAttr->pValue, *pLen = __ppsp_serv_char_ffd8_para_size );
      }
      break;

      default:
	      // Should never get here! (characteristics 3 and 4 do not have read permissions)
	      *pLen = 0;
	      status = ATT_ERR_ATTR_NOT_FOUND;
	      break;
    }
  } else {
    // 128-bit UUID
    *pLen = 0;
    status = ATT_ERR_INVALID_HANDLE;
  }

  return ( status );
}

/*********************************************************************
 * @fn      simpleProfile_WriteAttrCB
 *
 * @brief   Validate attribute data prior to a write operation
 *
 * @param   connHandle - connection message was received on
 * @param   pAttr - pointer to attribute
 * @param   pValue - pointer to data to be written
 * @param   len - length of data
 * @param   offset - offset of the first octet to be written
 *
 * @return  Success or Failure
 */
 // TODO: test this function
static bStatus_t ppsp_serv_set_attr( uint16 connHandle, gattAttribute_t *pAttr,
                                 uint8 *pValue, uint8 len, uint16 offset )
{
  bStatus_t status = SUCCESS;
  uint8 upda_para = 0xFF;

  // LOG("[PANDA][ENT] %s: len:%d, offs:%d \n\r", __func__, len, offset);
  // printf("[PANDA][ENT] %s: len:%d, offs:%d \n\r", __func__, len, offset);
  // LOG("[PANDA][INF] mtu:%d", ATT_GetCurrentMTUSize());
  // LOG("\r\n[DUMP] >> "); for ( int itr0 = 0; itr0 < len; itr0 += 1 ) LOG("%02x,", pValue[itr0]); LOG("[DUMP] << \r\n");


  // If attribute permissions require authorization to write, return error
  if ( gattPermitAuthorWrite( pAttr->permissions ) ) {
    // Insufficient authorization
    return ( ATT_ERR_INSUFFICIENT_AUTHOR );
  }

  // Make sure it's not a blob operation (no attributes in the profile are long)
  // if ( 0 <  offset ) {
  //   return ( ATT_ERR_ATTR_NOT_LONG );
  // }

  if ( pAttr->type.len == ATT_BT_UUID_SIZE ) {
    // 16-bit UUID
    uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);

    switch ( uuid ) {
      case PPSP_SERV_CFGS_CHAR_FED4_UUID: {
        if ( PPSP_SERV_CFGS_CHAR_FED4_DLEN <= offset ) {
          status = ATT_ERR_INVALID_VALUE_SIZE;
        } else {
          // Write the value
          VOID osal_memcpy( pAttr->pValue + offset, pValue, len );
          upda_para = PPSP_SERV_CFGS_CHAR_FFD4_INDX;
        }
      }
      break;

      case PPSP_SERV_CFGS_CHAR_FED5_UUID: {
        if ( PPSP_SERV_CFGS_CHAR_FED5_DLEN <= offset ) {
          status = ATT_ERR_INVALID_VALUE_SIZE;
        } else {
          // Write the value
          VOID osal_memcpy( pAttr->pValue + offset, pValue, PPSP_SERV_CFGS_CHAR_FED5_DLEN );
          upda_para = PPSP_SERV_CFGS_CHAR_FFD5_INDX;
        }
      }
      break;

      case PPSP_SERV_CFGS_CHAR_FED6_UUID: {
        if ( PPSP_SERV_CFGS_CHAR_FED6_DLEN <= offset ) {
          status = ATT_ERR_INVALID_VALUE_SIZE;
        } else {
          // Write the value
          VOID osal_memcpy( pAttr->pValue + offset, pValue, PPSP_SERV_CFGS_CHAR_FED6_DLEN );
          upda_para = PPSP_SERV_CFGS_CHAR_FFD6_INDX;
        }
      }
      break;

      case PPSP_SERV_CFGS_CHAR_FED7_UUID: {
        if ( PPSP_SERV_CFGS_CHAR_FED7_DLEN <= offset ) {
          status = ATT_ERR_INVALID_VALUE_SIZE;
        } else {
          // Write the value
          VOID osal_memcpy( pAttr->pValue + offset, pValue, PPSP_SERV_CFGS_CHAR_FED7_DLEN );
          upda_para = PPSP_SERV_CFGS_CHAR_FFD7_INDX;
        }
      }
      break;

      case PPSP_SERV_CFGS_CHAR_FED8_UUID: {
        if ( PPSP_SERV_CFGS_CHAR_FED8_DLEN <= offset ) {
          status = ATT_ERR_INVALID_VALUE_SIZE;
        } else {
          // Write the value
          VOID osal_memcpy( pAttr->pValue + offset, pValue, PPSP_SERV_CFGS_CHAR_FED8_DLEN );
          upda_para = PPSP_SERV_CFGS_CHAR_FFD8_INDX;
        }
      }
      break;

      case GATT_CLIENT_CHAR_CFG_UUID: {
        // Validate/Write Temperature measurement setting
        if ( pAttr->handle == simpleProfileAttrTbl[7].handle ) {
            // LOG("[PANDA][INF] CHAR FED6 CFGS: %d \n\r", *pValue);
            uint16 valu;
            if ( 0 != *pValue ) valu = 0x02;
            else                valu = 0x00;
            status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, (uint8*)&valu, sizeof(valu),
                                                    offset, GATT_CLIENT_CFG_INDICATE );
        } else
        if ( pAttr->handle == simpleProfileAttrTbl[12].handle ) {
            // LOG("[PANDA][INF] CHAR FED8 CFGS: %d \n\r", *pValue);
            status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, pValue, 2,
                                                    offset, GATT_CLIENT_CFG_NOTIFY );
        }
      }
      break;

      default:
        // Should never get here! (characteristics 2 and 4 do not have write permissions)
        status = ATT_ERR_ATTR_NOT_FOUND;
        break;
    }
  } else {
    // 128-bit UUID
    status = ATT_ERR_INVALID_HANDLE;
  }

  // If a charactersitic value changed then callback function to notify application of change
  if ( upda_para != 0xFF &&
       NULL != simpleProfile_AppCBs &&
       NULL != simpleProfile_AppCBs->char_upda ) {
        simpleProfile_AppCBs->char_upda( upda_para, len );
  }

  return ( status );
}

/*********************************************************************
 * @fn          simpleProfile_HandleConnStatusCB
 *
 * @brief       Simple Profile link status change handler function.
 *
 * @param       conn_hdle - connection handle
 * @param       changeType - type of change
 *
 * @return      none
 */
static void ppsp_serv_hdlr_conn_stat( uint16 conn_hdle, uint8 chng_type )
{
  // Make sure this is not loopback connection
  if ( conn_hdle != LOOPBACK_CONNHANDLE ) {
    // Reset Client Char Config if connection has dropped
    if ( ( chng_type == LINKDB_STATUS_UPDATE_REMOVED )      ||
         ( ( chng_type == LINKDB_STATUS_UPDATE_STATEFLAGS ) &&
           ( !linkDB_Up( conn_hdle ) ) ) ) {
      GATTServApp_InitCharCfg( conn_hdle, __ppsp_serv_char_ffd6_cfgs );
      GATTServApp_InitCharCfg( conn_hdle, __ppsp_serv_char_ffd8_cfgs );

      ppsp_impl_ack_conn(0);  // ack upper impl loss of connection
    }
  }
}

/*********************************************************************
 * PROFILE CALLBACKS
 */
// Simple Profile Service Callbacks
CONST gattServiceCBs_t ppspCBs =
{
  ppsp_serv_get_attr,   // Read callback function pointer
  ppsp_serv_set_attr,   // Write callback function pointer
  NULL,                 // Authorization callback function pointer
};

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

/*********************************************************************
 * @fn      SimpleProfile_AddService
 *
 * @brief   Initializes the Simple Profile service by registering
 *          GATT attributes with the GATT server.
 *
 * @param   services - services to add. This is a bit map and can
 *                     contain more than one service.
 *
 * @return  Success or Failure
 */
bStatus_t ppsp_serv_add_serv(uint32 serv)
{
  uint8 status = SUCCESS;

  // Initialize Client Characteristic Configuration attributes
  GATTServApp_InitCharCfg( INVALID_CONNHANDLE, __ppsp_serv_char_ffd6_cfgs );
  GATTServApp_InitCharCfg( INVALID_CONNHANDLE, __ppsp_serv_char_ffd8_cfgs );

  // Register with Link DB to receive link status change callback
  VOID linkDB_Register( ppsp_serv_hdlr_conn_stat );

  if ( serv & PPSP_SERV_CFGS_SERV_FEB3_MASK )
  {
    // Register GATT attribute list and CBs with GATT Server App
    status = GATTServApp_RegisterService( simpleProfileAttrTbl,
                                          GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                          &ppspCBs );
  }

  // for (int i = 0; i < PPSP_SERV_CFGS_CHAR_FED4_DLEN; i++)
  // {
  //   __ppsp_serv_char_FFD4_para[i] =i;
  // }


  return ( status );
}


/*********************************************************************
 * @fn      SimpleProfile_RegisterAppCBs
 *
 * @brief   Registers the application callback function. Only call
 *          this function once.
 *
 * @param   callbacks - pointer to application callbacks.
 *
 * @return  SUCCESS or bleAlreadyInRequestedMode
 */
bStatus_t ppsp_serv_reg_appl( ppsp_serv_appl_CBs_t *appCallbacks )
{
  if ( appCallbacks ) {
    simpleProfile_AppCBs = appCallbacks;

    return ( SUCCESS );
  }
  else
  {
    return ( bleAlreadyInRequestedMode );
  }
}


/*********************************************************************
 * @fn      SimpleProfile_SetParameter
 *
 * @brief   Set a Simple Profile parameter.
 *
 * @param   param - Profile parameter ID
 * @param   len - length of data to right
 * @param   value - pointer to data to write.  This is dependent on
 *          the parameter ID and WILL be cast to the appropriate
 *          data type (example: data type of uint16 will be cast to
 *          uint16 pointer).
 *
 * @return  bStatus_t
 */
bStatus_t ppsp_serv_set_para( uint8 para, uint8 leng, void *valu )
{
    // LOG("[PANDA][ENT] %s: para:%d, leng:%d, valu:%x \n\r", __func__, para, leng, valu);
    // LOG("\r\n[DUMP] >> "); for ( int itr0 = 0; itr0 < leng; itr0 += 1 ) LOG("%02x,", ((uint8*)valu)[itr0]); LOG("[DUMP] << \r\n");

    bStatus_t ret = SUCCESS;
    switch ( para ) {
        case PPSP_SERV_CFGS_CHAR_FFD4_INDX: {
            if ( leng <= PPSP_SERV_CFGS_CHAR_FED4_DLEN ) {
                osal_memcpy(__ppsp_serv_char_ffd4_para, valu, __ppsp_serv_char_ffd4_para_size = leng);
            } else {
                ret = bleInvalidRange;
            }
        }
    break;

    // case PPSP_SERV_CFGS_CHAR_2_INDX:
    //   if ( len <= PPSP_SERV_CFGS_CHAR_2_DLEN )
    //   {
    //     osal_memcpy(__ppsp_serv_char_2_para, value, len);
    //   }
    //   else
    //   {
    //     ret = bleInvalidRange;
    //   }
    //   break;

    // case PPSP_SERV_CFGS_CHAR_3_INDX:
    //   if ( len == sizeof ( uint16 ) )
    //   {
    //     // simpleProfileChar3 = (*(uint8 *)value) << 8 | *((uint8 *)value + 1);
    //   }
    //   else
    //   {
    //     ret = bleInvalidRange;
    //   }
    //   break;

    case PPSP_SERV_CFGS_CHAR_FFD6_INDX: {
        uint16 cfgs = GATTServApp_ReadCharCfg( 0, __ppsp_serv_char_ffd6_cfgs );

        if ( GATT_CLIENT_CFG_INDICATE == cfgs ) {
            if ( leng <= PPSP_SERV_CFGS_CHAR_FED6_DLEN ) {
                osal_memcpy( __ppsp_serv_char_ffd6_para, valu, __ppsp_serv_char_ffd6_para_size = leng );

                // send Noti/Indi if enabled
                GATTServApp_ProcessCharCfg( __ppsp_serv_char_ffd6_cfgs,
                                            __ppsp_serv_char_ffd6_para,
                                            FALSE,
                                            simpleProfileAttrTbl,
                                            GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                            INVALID_TASK_ID );
				/* send_notity_indication( __ppsp_serv_char_ffd6_cfgs,
                                            __ppsp_serv_char_ffd6_para,
                                            FALSE,
                                            simpleProfileAttrTbl,
                                            GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                            INVALID_TASK_ID,__ppsp_serv_char_ffd6_para_size ); */
            } else {
                ret = bleInvalidRange;
            }
        }
    }
    break;

    // case PPSP_SERV_CFGS_CHAR_5_INDX:
      // if ( leng == sizeof ( uint8 ) )
      // {
      //   // simpleProfileChar5 = *((uint8*)value);
      // }
      // else
      // {
      //   ret = bleInvalidRange;
      // }
      // break;

      case PPSP_SERV_CFGS_CHAR_FFD8_INDX: {
        uint16 cfgs = GATTServApp_ReadCharCfg( 0, __ppsp_serv_char_ffd8_cfgs );

        if ( GATT_CLIENT_CFG_NOTIFY == cfgs ) {
            if ( leng <= PPSP_SERV_CFGS_CHAR_FED8_DLEN ) {
                osal_memcpy( __ppsp_serv_char_ffd8_para, valu, __ppsp_serv_char_ffd8_para_size = leng );

                // send Noti/Indi if enabled
                GATTServApp_ProcessCharCfg( __ppsp_serv_char_ffd8_cfgs,
                                            __ppsp_serv_char_ffd8_para,
                                            FALSE,
                                            simpleProfileAttrTbl,
                                            GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                            INVALID_TASK_ID );
				        /* send_notity_indication( __ppsp_serv_char_ffd8_cfgs,
                                            __ppsp_serv_char_ffd8_para,
                                            FALSE,
                                            simpleProfileAttrTbl,
                                            GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                            INVALID_TASK_ID,__ppsp_serv_char_ffd8_para_size ); */
            } else {
                ret = bleInvalidRange;
            }
        }
    }
    break;

    default:
      ret = INVALIDPARAMETER;
      break;
  }

  return ( ret );
}

/*********************************************************************
 * @fn      SimpleProfile_GetParameter
 *
 * @brief   Get a Simple Profile parameter.
 *
 * @param   param - Profile parameter ID
 * @param   value - pointer to data to put.  This is dependent on
 *          the parameter ID and WILL be cast to the appropriate
 *          data type (example: data type of uint16 will be cast to
 *          uint16 pointer).
 *
 * @return  bStatus_t
 */
bStatus_t ppsp_serv_get_para( uint8 para, void *valu, uint8 leng )
{
  bStatus_t ret = SUCCESS;

  switch ( para ) {
    case PPSP_SERV_CFGS_CHAR_FFD4_INDX:
      VOID osal_memcpy( valu, __ppsp_serv_char_ffd4_para, leng );
      break;

    case PPSP_SERV_CFGS_CHAR_FFD5_INDX:
      VOID osal_memcpy( valu, __ppsp_serv_char_ffd5_para, leng );
      break;

    case PPSP_SERV_CFGS_CHAR_FFD6_INDX:
      // *((uint16*)value) = simpleProfileChar3;
      break;

    case PPSP_SERV_CFGS_CHAR_FFD7_INDX:
      VOID osal_memcpy( valu, __ppsp_serv_char_ffd7_para, leng );
      break;

    case PPSP_SERV_CFGS_CHAR_FFD8_INDX:
      // *((uint8*)value) = simpleProfileChar5;
      break;

    default:
      ret = INVALIDPARAMETER;
      break;
  }

  return ( ret );
}


/* static bStatus_t send_notity_indication( gattCharCfg_t *charCfgTbl, uint8 *pValue,
                                      uint8 authenticated, gattAttribute_t *attrTbl,
                                      uint16 numAttrs, uint8 taskId,uint8 dlen)
{
  bStatus_t status = SUCCESS;

  for ( uint8 i = 0; i < GATT_MAX_NUM_CONN; i++ )
  {
    gattCharCfg_t *pItem = &(charCfgTbl[i]);

    if ( ( pItem->connHandle != INVALID_CONNHANDLE ) &&
         ( pItem->value != GATT_CFG_NO_OPERATION ) )
    {
      gattAttribute_t *pAttr;

      // Find the characteristic value attribute
      pAttr = GATTServApp_FindAttr( attrTbl, numAttrs, pValue );
      if ( pAttr != NULL )
      {
        attHandleValueNoti_t noti;

        // If the attribute value is longer than (ATT_MTU - 3) octets, then
        // only the first (ATT_MTU - 3) octets of this attributes value can
        // be sent in a notification.
        if ( GATTServApp_ReadAttr( pItem->connHandle, pAttr,
                                   GATT_SERVICE_HANDLE( attrTbl ), noti.value,
                                   &noti.len, 0, (g_ATT_MTU_SIZE-3) ) == SUCCESS )
        {
          noti.handle = pAttr->handle;

          if(dlen)
            noti.len=dlen;

          if ( pItem->value & GATT_CLIENT_CFG_NOTIFY )
          {
            status |= GATT_Notification( pItem->connHandle, &noti, authenticated );
          }

          if ( pItem->value & GATT_CLIENT_CFG_INDICATE )
          {
            status |= GATT_Indication( pItem->connHandle, (attHandleValueInd_t *)&noti,
                                       authenticated, taskId );
          }
        }
      }
    }
  } // for

  return ( status );
} */

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