/*************************************************************************************************/
/*!
 *  \file   svc_hid.c
 *        
 *  \brief  Human Interface Device service implementation.
 *
 *          $Date: 2017-02-07 19:05:49 -0600 (Tue, 07 Feb 2017) $
 *          $Revision: 11110 $
 *  
 *  Copyright (c) 2015-2016-2017 ARM Ltd., all rights reserved.
 *  ARM Ltd. confidential and proprietary.
 *
 *  IMPORTANT.  Your use of this file is governed by a Software License Agreement
 *  ("Agreement") that must be accepted in order to download or otherwise receive a
 *  copy of this file.  You may not use or copy this file for any purpose other than
 *  as described in the Agreement.  If you do not agree to all of the terms of the
 *  Agreement do not use this file and delete all copies in your possession or control;
 *  if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
 *  to any use, copying or further distribution of this software.
 */
/*************************************************************************************************/

#include <string.h>
#include "wsf_types.h"
#include "bstream.h"
#include "att_api.h"
#include "svc_hid.h"
#include "wsf_trace.h"
#include "svc_ch.h"
#include "svc_cfg.h"
#include "svc_batt.h"

/**************************************************************************************************
  Macros
**************************************************************************************************/

/*! Characteristic read permissions */
#ifndef HID_SEC_PERMIT_READ
#define HID_SEC_PERMIT_READ (ATTS_PERMIT_READ | ATTS_PERMIT_READ_ENC)
#endif

/*! Characteristic write permissions */
#ifndef HID_SEC_PERMIT_WRITE
#define HID_SEC_PERMIT_WRITE (ATTS_PERMIT_WRITE | ATTS_PERMIT_WRITE_ENC)
#endif

/**************************************************************************************************
 Static Variables
**************************************************************************************************/

/* UUIDs */

/**************************************************************************************************
 Service variables
**************************************************************************************************/

/* Proprietary Service Declaration */
static const uint8_t hidValSvc[] = {UINT16_TO_BYTES(ATT_UUID_HID_SERVICE)};
static const uint16_t hidLenSvc = sizeof(hidValSvc);


/* HID Info Characteristic */
static const uint8_t hidInfoCh[] = {ATT_PROP_READ, UINT16_TO_BYTES(HID_INFO_HDL), UINT16_TO_BYTES(ATT_UUID_HID_INFORMATION)};
static const uint16_t hidLenInfoCh = sizeof(hidInfoCh);

/* HID Info Value: HID Spec version, country code, flags */
static const uint8_t hidInfoVal[] = {UINT16_TO_BYTES(HID_VERSION), 0x00, 0x00};
static const uint16_t hidLenInfoVal = sizeof(hidInfoVal);


/* HID Report Map Characteristic */
static const uint8_t hidRmCh[] = {ATT_PROP_READ, UINT16_TO_BYTES(HID_REPORT_MAP_HDL), UINT16_TO_BYTES(ATT_UUID_HID_REPORT_MAP)};
static const uint16_t hidLenRmCh = sizeof(hidRmCh);

/* HID Report Map Value */
/* Note: The hidReportMap and hidReportMapLen variables should be defined in the application */
extern const uint8_t hidReportMap[];
extern const uint16_t hidReportMapLen;

/* HID External Report Reference Descriptor */
static const uint8_t hidExtReport[] = {UINT16_TO_BYTES(ATT_UUID_BATTERY_LEVEL)};
static const uint16_t hidLenExtReport = sizeof(hidExtReport);


/* HID Control Point Characteristic */
static const uint8_t hidCpCh[] = {ATT_PROP_WRITE_NO_RSP, UINT16_TO_BYTES(HID_CONTROL_POINT_HDL), UINT16_TO_BYTES(ATT_UUID_HID_CONTROL_POINT)};
static const uint16_t hidLenCpCh = sizeof(hidCpCh);

/* HID Control Point Value */
static uint8_t hidCpVal[] = {0};
static const uint16_t hidLenCpVal = sizeof(hidCpVal);


/* HID Boot Keyboard In Characteristic */
static const uint8_t hidBkiCh[] = {ATT_PROP_READ | ATT_PROP_NOTIFY, UINT16_TO_BYTES(HID_KEYBOARD_BOOT_IN_HDL), UINT16_TO_BYTES(ATT_UUID_HID_BOOT_KEYBOARD_IN)};
static const uint16_t hidLenBkiCh = sizeof(hidBkiCh);

/* HID Boot Keyboard In Value */
static uint8_t hidBkiVal[HID_MAX_REPORT_LEN];
static uint16_t hidLenBkiVal = sizeof(hidBkiVal);

/* HID Boot Keyboard In client characteristic configuration */
static uint8_t hidValBkiChCcc[] = {UINT16_TO_BYTES(0x0000)};
static const uint16_t hidLenBkiChCcc = sizeof(hidValBkiChCcc);


/* HID Boot Keyboard Out Characteristic */
static const uint8_t hidBkoCh[] = {ATT_PROP_READ | ATT_PROP_WRITE | ATT_PROP_WRITE_NO_RSP, UINT16_TO_BYTES(HID_KEYBOARD_BOOT_OUT_HDL), UINT16_TO_BYTES(ATT_UUID_HID_BOOT_KEYBOARD_OUT)};
static const uint16_t hidLenBkoCh = sizeof(hidBkoCh);

/* HID Boot Keyboard Out Value */
static uint8_t hidBkoVal[HID_MAX_REPORT_LEN];
static uint16_t hidLenBkoVal = sizeof(hidBkoVal);


/* HID Boot Mouse In Characteristic */
static const uint8_t hidBmiCh[] = {ATT_PROP_READ | ATT_PROP_NOTIFY, UINT16_TO_BYTES(HID_MOUSE_BOOT_IN_HDL), UINT16_TO_BYTES(ATT_UUID_HID_BOOT_MOUSE_IN)};
static const uint16_t hidLenBmiCh = sizeof(hidBmiCh);

/* HID Boot Mouse In Value */
static uint8_t hidBmiVal[HID_MAX_REPORT_LEN];
static uint16_t hidLenBmiVal = sizeof(hidBmiVal);

/* HID Boot Mouse In client characteristic configuration */
static uint8_t hidValBmiChCcc[] = {UINT16_TO_BYTES(0x0000)};
static const uint16_t hidLenBmiChCcc = sizeof(hidValBmiChCcc);


/* HID Input Report #1 Characteristic */
static const uint8_t hidIRep1Ch[] = {ATT_PROP_READ | ATT_PROP_NOTIFY, UINT16_TO_BYTES(HID_INPUT_REPORT_1_HDL), UINT16_TO_BYTES(ATT_UUID_HID_REPORT)};
static const uint16_t hidLenIRep1Ch = sizeof(hidIRep1Ch);

/* HID Input Report Value */
static uint8_t hidIRep1Val[HID_MAX_REPORT_LEN];
static uint16_t hidLenIRep1Val = sizeof(hidIRep1Val);

/* HID Input Report client characteristic configuration */
static uint8_t hidValIRep1ChCcc[] = {UINT16_TO_BYTES(0x0000)};
static const uint16_t hidLenIRep1ChCcc = sizeof(hidValIRep1ChCcc);

/* HID Input Report Reference - ID, Type */
static const uint8_t hidValIRep1IdMap[] = {0x01, HID_REPORT_TYPE_INPUT};
static const uint16_t hidLenIRep1IdMap = sizeof(hidValIRep1IdMap);


/* HID Input Report #2 Characteristic */
static const uint8_t hidIRep2Ch[] = {ATT_PROP_READ | ATT_PROP_NOTIFY, UINT16_TO_BYTES(HID_INPUT_REPORT_2_HDL), UINT16_TO_BYTES(ATT_UUID_HID_REPORT)};
static const uint16_t hidLenIRep2Ch = sizeof(hidIRep2Ch);

/* HID Input Report Value */
static uint8_t hidIRep2Val[HID_MAX_REPORT_LEN];
static uint16_t hidLenIRep2Val = sizeof(hidIRep2Val);

/* HID Input Report client characteristic configuration */
static uint8_t hidValIRep2ChCcc[] = {UINT16_TO_BYTES(0x0000)};
static const uint16_t hidLenIRep2ChCcc = sizeof(hidValIRep2ChCcc);

/* HID Input Report Reference - ID, Type */
static const uint8_t hidValIRep2IdMap[] = {0x02, HID_REPORT_TYPE_INPUT};
static const uint16_t hidLenIRep2IdMap = sizeof(hidValIRep2IdMap);


/* HID Input Report #3 Characteristic */
static const uint8_t hidIRep3Ch[] = {ATT_PROP_READ | ATT_PROP_NOTIFY, UINT16_TO_BYTES(HID_INPUT_REPORT_3_HDL), UINT16_TO_BYTES(ATT_UUID_HID_REPORT)};
static const uint16_t hidLenIRep3Ch = sizeof(hidIRep3Ch);

/* HID Input Report Value */
static uint8_t hidIRep3Val[HID_MAX_REPORT_LEN];
static uint16_t hidLenIRep3Val = sizeof(hidIRep3Val);

/* HID Input Report client characteristic configuration */
static uint8_t hidValIRep3ChCcc[] = {UINT16_TO_BYTES(0x0000)};
static const uint16_t hidLenIRep3ChCcc = sizeof(hidValIRep3ChCcc);

/* HID Input Report Reference - ID, Type */
static const uint8_t hidValIRep3IdMap[] = {0x03, HID_REPORT_TYPE_INPUT};
static const uint16_t hidLenIRep3IdMap = sizeof(hidValIRep3IdMap);


/* HID Output Report Characteristic */
static const uint8_t hidORepCh[] = {ATT_PROP_READ | ATT_PROP_WRITE | ATT_PROP_WRITE_NO_RSP, UINT16_TO_BYTES(HID_OUTPUT_REPORT_HDL), UINT16_TO_BYTES(ATT_UUID_HID_REPORT)};
static const uint16_t hidLenORepCh = sizeof(hidORepCh);

/* HID Output Report Value */
static uint8_t hidORepVal[HID_MAX_REPORT_LEN];
static uint16_t hidLenORepVal = sizeof(hidORepVal);

/* HID Output Report Reference - ID, Type */
static const uint8_t hidValORepIdMap[] = {0x00, HID_REPORT_TYPE_OUTPUT};
static const uint16_t hidLenORepIdMap = sizeof(hidValORepIdMap);


/* HID Feature Report Characteristic */
static const uint8_t hidFRepCh[] = {ATT_PROP_READ | ATT_PROP_WRITE, UINT16_TO_BYTES(HID_FEATURE_REPORT_HDL), UINT16_TO_BYTES(ATT_UUID_HID_REPORT)};
static const uint16_t hidLenFRepCh = sizeof(hidFRepCh);

/* HID Feature Report Value */
static uint8_t hidFRepVal[HID_MAX_REPORT_LEN];
static uint16_t hidLenFRepVal = sizeof(hidFRepVal);

/* HID Feature Report Reference - ID, Type */
static const uint8_t hidValFRepIdMap[] = {0x00, HID_REPORT_TYPE_FEATURE};
static const uint16_t hidLenFRepIdMap = sizeof(hidValFRepIdMap);


/* HID Protocol Mode Characteristic */
static const uint8_t hidPmCh[] = {ATT_PROP_READ | ATT_PROP_WRITE_NO_RSP, UINT16_TO_BYTES(HID_PROTOCOL_MODE_HDL), UINT16_TO_BYTES(ATT_UUID_HID_PROTOCOL_MODE)};
static const uint16_t hidLenPmCh = sizeof(hidPmCh);

/* HID Protocol Mode Value */
static uint8_t hidPmVal[] = {HID_PROTOCOL_MODE_REPORT};
static const uint16_t hidLenPmVal = sizeof(hidPmVal);


/* Attribute list for HID group */
static const attsAttr_t hidList[] =
{
  /* Service Delcaration */
  {
    attPrimSvcUuid, 
    (uint8_t *) hidValSvc,
    (uint16_t *) &hidLenSvc, 
    sizeof(hidValSvc),
    0,
    ATTS_PERMIT_READ
  },

  {
    attChUuid,
    (uint8_t *) hidInfoCh,
    (uint16_t *) &hidLenInfoCh,
    sizeof(hidInfoCh),
    0,
    ATTS_PERMIT_READ
  },
  {
    attHidiChUuid,
    (uint8_t *) hidInfoVal,
    (uint16_t *) &hidLenInfoVal,
    sizeof(hidInfoVal),
    0,
    HID_SEC_PERMIT_READ
  },

  {
    attChUuid,
    (uint8_t *) hidRmCh,
    (uint16_t *) &hidLenRmCh,
    sizeof(hidRmCh),
    0,
    ATTS_PERMIT_READ
  },
  {
    attHidRmChUuid,
    (uint8_t *) hidReportMap,
    (uint16_t *) &hidReportMapLen,
    HID_MAX_REPORT_MAP_LEN,
    ATTS_SET_VARIABLE_LEN,
    HID_SEC_PERMIT_READ
  },
  {
    attHidErmUuid,
    (uint8_t *) hidExtReport,
    (uint16_t *) &hidLenExtReport,
    sizeof(hidExtReport),
    0,
    HID_SEC_PERMIT_READ
  },

  {
    attChUuid,
    (uint8_t *) hidCpCh,
    (uint16_t *) &hidLenCpCh,
    sizeof(hidCpCh),
    0,
    ATTS_PERMIT_READ
  },
  {
    attHidRepChUuid,
    (uint8_t *) hidCpVal,
    (uint16_t *) &hidLenCpVal,
    sizeof(hidCpVal),
    ATTS_SET_WRITE_CBACK,
    HID_SEC_PERMIT_WRITE
  },

  {
    attChUuid,
    (uint8_t *) hidBkiCh,
    (uint16_t *) &hidLenBkiCh,
    sizeof(hidBkiCh),
    0,
    ATTS_PERMIT_READ
  },
  {
    attHidBkiChUuid,
    (uint8_t *) hidBkiVal,
    (uint16_t *) &hidLenBkiVal,
    sizeof(hidBkiVal),
    ATTS_SET_VARIABLE_LEN,
    HID_SEC_PERMIT_READ
  },
  {
    attCliChCfgUuid,
    (uint8_t *) hidValBkiChCcc,
    (uint16_t *) &hidLenBkiChCcc,
    sizeof(hidValBkiChCcc),
    ATTS_SET_CCC,
    (HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE)
  },

  {
    attChUuid,
    (uint8_t *) hidBkoCh,
    (uint16_t *) &hidLenBkoCh,
    sizeof(hidBkoCh),
    0,
    ATTS_PERMIT_READ
  },
  {
    attHidBkoChUuid,
    (uint8_t *) hidBkoVal,
    (uint16_t *) &hidLenBkoVal,
    sizeof(hidBkoVal),
    (ATTS_SET_WRITE_CBACK | ATTS_SET_VARIABLE_LEN),
    (HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE)
  },

  {
    attChUuid,
    (uint8_t *) hidBmiCh,
    (uint16_t *) &hidLenBmiCh,
    sizeof(hidBmiCh),
    0,
    ATTS_PERMIT_READ
  },
  {
    attHidBmiChUuid,
    (uint8_t *) hidBmiVal,
    (uint16_t *) &hidLenBmiVal,
    sizeof(hidBmiVal),
    ATTS_SET_VARIABLE_LEN,
    HID_SEC_PERMIT_READ
  },
  {
    attCliChCfgUuid,
    (uint8_t *) hidValBmiChCcc,
    (uint16_t *) &hidLenBmiChCcc,
    sizeof(hidValBmiChCcc),
    ATTS_SET_CCC,
    (HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE)
  },

  {
    attChUuid,
    (uint8_t *) hidIRep1Ch,
    (uint16_t *) &hidLenIRep1Ch,
    sizeof(hidIRep1Ch),
    0,
    ATTS_PERMIT_READ
  },
  {
    attHidRepChUuid,
    (uint8_t *) hidIRep1Val,
    (uint16_t *) &hidLenIRep1Val,
    sizeof(hidIRep1Val),
    ATTS_SET_VARIABLE_LEN,
    HID_SEC_PERMIT_READ
  },
  {
    attCliChCfgUuid,
    (uint8_t *) hidValIRep1ChCcc,
    (uint16_t *) &hidLenIRep1ChCcc,
    sizeof(hidValIRep1ChCcc),
    ATTS_SET_CCC,
    (HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE)
  },
  {
    attHidRimUuid,
    (uint8_t *) hidValIRep1IdMap,
    (uint16_t *) &hidLenIRep1IdMap,
    sizeof(hidValIRep1IdMap),
    0,
    HID_SEC_PERMIT_READ
  },

  {
    attChUuid,
    (uint8_t *) hidIRep2Ch,
    (uint16_t *) &hidLenIRep2Ch,
    sizeof(hidIRep2Ch),
    0,
    ATTS_PERMIT_READ
  },
  {
    attHidRepChUuid,
    (uint8_t *) hidIRep2Val,
    (uint16_t *) &hidLenIRep2Val,
    sizeof(hidIRep2Val),
    ATTS_SET_VARIABLE_LEN,
    HID_SEC_PERMIT_READ
  },
  {
    attCliChCfgUuid,
    (uint8_t *) hidValIRep2ChCcc,
    (uint16_t *) &hidLenIRep2ChCcc,
    sizeof(hidValIRep2ChCcc),
    ATTS_SET_CCC,
    (HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE)
  },
  {
    attHidRimUuid,
    (uint8_t *) hidValIRep2IdMap,
    (uint16_t *) &hidLenIRep2IdMap,
    sizeof(hidValIRep2IdMap),
    0,
    HID_SEC_PERMIT_READ
  },

  {
    attChUuid,
    (uint8_t *) hidIRep3Ch,
    (uint16_t *) &hidLenIRep3Ch,
    sizeof(hidIRep3Ch),
    0,
    ATTS_PERMIT_READ
  },
  {
    attHidRepChUuid,
    (uint8_t *) hidIRep3Val,
    (uint16_t *) &hidLenIRep3Val,
    sizeof(hidIRep3Val),
    ATTS_SET_VARIABLE_LEN,
    HID_SEC_PERMIT_READ
  },
  {
    attCliChCfgUuid,
    (uint8_t *) hidValIRep3ChCcc,
    (uint16_t *) &hidLenIRep3ChCcc,
    sizeof(hidValIRep3ChCcc),
    ATTS_SET_CCC,
    (HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE)
  },
  {
    attHidRimUuid,
    (uint8_t *) hidValIRep3IdMap,
    (uint16_t *) &hidLenIRep3IdMap,
    sizeof(hidValIRep3IdMap),
    0,
    HID_SEC_PERMIT_READ
  },

  {
    attChUuid,
    (uint8_t *) hidORepCh,
    (uint16_t *) &hidLenORepCh,
    sizeof(hidORepCh),
    0,
    ATTS_PERMIT_READ
  },
  {
    attHidRepChUuid,
    (uint8_t *) hidORepVal,
    (uint16_t *) &hidLenORepVal,
    sizeof(hidORepVal),
    (ATTS_SET_WRITE_CBACK | ATTS_SET_VARIABLE_LEN),
    (HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE)
  },
  {
    attHidRimUuid,
    (uint8_t *) hidValORepIdMap,
    (uint16_t *) &hidLenORepIdMap,
    sizeof(hidValORepIdMap),
    0,
    HID_SEC_PERMIT_READ
  },

  {
    attChUuid,
    (uint8_t *) hidFRepCh,
    (uint16_t *) &hidLenFRepCh,
    sizeof(hidFRepCh),
    0,
    ATTS_PERMIT_READ
  },
  {
    attHidRepChUuid,
    (uint8_t *) hidFRepVal,
    (uint16_t *) &hidLenFRepVal,
    sizeof(hidFRepVal),
    (ATTS_SET_WRITE_CBACK | ATTS_SET_VARIABLE_LEN),
    (HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE)
  },
  {
    attHidRimUuid,
    (uint8_t *) hidValFRepIdMap,
    (uint16_t *) &hidLenFRepIdMap,
    sizeof(hidValFRepIdMap),
    0,
    HID_SEC_PERMIT_READ
  },

  {
    attChUuid,
    (uint8_t *) hidPmCh,
    (uint16_t *) &hidLenPmCh,
    sizeof(hidPmCh),
    0,
    ATTS_PERMIT_READ
  },
  {
    attHidRepChUuid,
    (uint8_t *) hidPmVal,
    (uint16_t *) &hidLenPmVal,
    sizeof(hidPmVal),
    ATTS_SET_WRITE_CBACK,
    (HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE)
  }
};

/* HID group structure */
static attsGroup_t svcHidkbGroup =
{
  NULL,
  (attsAttr_t *) hidList,
  NULL,
  NULL,
  HID_START_HDL,
  HID_END_HDL
};

/*************************************************************************************************/
/*!
 *  \fn     SvcHidAddGroup
 *        
 *  \brief  Add the services from the attribute server.
 *
 *  \return None.
 */
/*************************************************************************************************/
void SvcHidAddGroup(void)
{
  AttsAddGroup(&svcHidkbGroup);
}

/*************************************************************************************************/
/*!
 *  \fn     SvcHidRemoveGroup
 *        
 *  \brief  Remove the services from the attribute server.
 *
 *  \return None.
 */
/*************************************************************************************************/
void SvcHidRemoveGroup(void)
{
  AttsRemoveGroup(HID_START_HDL);
}

/*************************************************************************************************/
/*!
 *  \fn     SvcHidRegister
 *        
 *  \brief  Register a read and write callback functions for the ATT Group.
 *
 *  \param  writeCb   Write callback function
 *  \param  readCb    Read callback function
 *
 *  \return None.
 */
/*************************************************************************************************/
void SvcHidRegister(attsWriteCback_t writeCb, attsReadCback_t readCb)
{
  svcHidkbGroup.writeCback = writeCb;
  svcHidkbGroup.readCback = readCb;
}

#if 0
/*************************************************************************************************/
/*!
 *  \fn     SvcHidAddGroupDyn
 *
 *  \brief  Add the Hid Service using the dynamic attribute subsystem.
 *
 *  \return None.
 */
/*************************************************************************************************/
void *SvcHidAddGroupDyn()
{
  void *pSHdl;
  uint8_t initCcc[] = {UINT16_TO_BYTES(0x0000)};

  /* Create the service */
  pSHdl = AttsDynCreateGroup(HID_START_HDL, HID_END_HDL);

  /* Primary service */
  AttsDynAddAttrConst(pSHdl, attPrimSvcUuid, hidValSvc, sizeof(hidValSvc), 0, ATTS_PERMIT_READ);

  /* HID Info */
  AttsDynAddAttrConst(pSHdl, attChUuid, hidInfoCh, sizeof(hidInfoCh), 0, ATTS_PERMIT_READ);
  AttsDynAddAttrConst(pSHdl, attHidiChUuid, hidInfoVal, sizeof(hidInfoVal), 0, HID_SEC_PERMIT_READ);

  /* HID Report Map */
  AttsDynAddAttrConst(pSHdl, attChUuid, hidRmCh, sizeof(hidRmCh), 0, ATTS_PERMIT_READ);
  AttsDynAddAttrConst(pSHdl, attHidRmChUuid, hidReportMap, hidReportMapLen, 0, HID_SEC_PERMIT_READ);

  /* HID External Report Reference */
  AttsDynAddAttrConst(pSHdl, attHidErmUuid, hidExtReport, sizeof(hidExtReport), 0, HID_SEC_PERMIT_READ);

  /* HID Control Point */
  AttsDynAddAttrConst(pSHdl, attChUuid, hidCpCh, sizeof(hidCpCh), 0, ATTS_PERMIT_READ);
  AttsDynAddAttr(pSHdl, attHidRepChUuid, NULL, 1, 1, ATTS_SET_WRITE_CBACK, HID_SEC_PERMIT_WRITE);

  /* HID Boot Keyboard In */
  AttsDynAddAttrConst(pSHdl, attChUuid, hidBkiCh, sizeof(hidBkiCh), 0, ATTS_PERMIT_READ);
  AttsDynAddAttr(pSHdl, attHidBkiChUuid, NULL, HID_MAX_REPORT_LEN, HID_MAX_REPORT_LEN, 
                      ATTS_SET_VARIABLE_LEN, HID_SEC_PERMIT_READ);
  AttsDynAddAttr(pSHdl, attCliChCfgUuid, initCcc, sizeof(uint16_t), sizeof(uint16_t),
                      ATTS_SET_CCC, HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE);

  /* HID Boot Keyboard Out */
  AttsDynAddAttrConst(pSHdl, attChUuid, hidBkoCh, sizeof(hidBkoCh), 0, ATTS_PERMIT_READ);
  AttsDynAddAttr(pSHdl, attHidBkoChUuid, NULL, HID_MAX_REPORT_LEN, HID_MAX_REPORT_LEN,
      ATTS_SET_WRITE_CBACK | ATTS_SET_VARIABLE_LEN, HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE);

  /* HID Boot Mouse In */
  AttsDynAddAttrConst(pSHdl, attChUuid, hidBmiCh, sizeof(hidBmiCh), 0, ATTS_PERMIT_READ);
  AttsDynAddAttr(pSHdl, attHidBmiChUuid, NULL, HID_MAX_REPORT_LEN, HID_MAX_REPORT_LEN, 
                      ATTS_SET_VARIABLE_LEN, HID_SEC_PERMIT_READ);
  AttsDynAddAttr(pSHdl, attCliChCfgUuid, initCcc, sizeof(uint16_t), sizeof(uint16_t),
                      ATTS_SET_CCC, HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE);

  /* HID Input Report #1 (HIDAPP_REMOTE_REPORT_ID) */
  AttsDynAddAttrConst(pSHdl, attChUuid, hidIRep1Ch, sizeof(hidIRep1Ch), 0, ATTS_PERMIT_READ);
  AttsDynAddAttr(pSHdl, attHidRepChUuid, NULL, HID_MAX_REPORT_LEN, HID_MAX_REPORT_LEN, 
                      ATTS_SET_VARIABLE_LEN, HID_SEC_PERMIT_READ);
  AttsDynAddAttr(pSHdl, attCliChCfgUuid, initCcc, sizeof(uint16_t), sizeof(uint16_t),
                      ATTS_SET_CCC, HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE);
  AttsDynAddAttrConst(pSHdl, attHidRimUuid, hidValIRep1IdMap, sizeof(hidValIRep1IdMap), 
                      0, HID_SEC_PERMIT_READ);

  /* HID Input Report #2 (HIDAPP_KEYBOARD_REPORT_ID) */
  AttsDynAddAttrConst(pSHdl, attChUuid, hidIRep2Ch, sizeof(hidIRep2Ch), 0, ATTS_PERMIT_READ);
  AttsDynAddAttr(pSHdl, attHidRepChUuid, NULL, HID_MAX_REPORT_LEN, HID_MAX_REPORT_LEN, 
                      ATTS_SET_VARIABLE_LEN, HID_SEC_PERMIT_READ);
  AttsDynAddAttr(pSHdl, attCliChCfgUuid, initCcc, sizeof(uint16_t), sizeof(uint16_t),
                      ATTS_SET_CCC, HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE);
  AttsDynAddAttrConst(pSHdl, attHidRimUuid, hidValIRep2IdMap, sizeof(hidValIRep2IdMap),
                      0, HID_SEC_PERMIT_READ);

  /* HID Input Report #3 (HIDAPP_MOUSE_REPORT_ID) */
  AttsDynAddAttrConst(pSHdl, attChUuid, hidIRep3Ch, sizeof(hidIRep3Ch), 0, ATTS_PERMIT_READ);
  AttsDynAddAttr(pSHdl, attHidRepChUuid, NULL, HID_MAX_REPORT_LEN, HID_MAX_REPORT_LEN, 
                      ATTS_SET_VARIABLE_LEN, HID_SEC_PERMIT_READ);
  AttsDynAddAttr(pSHdl, attCliChCfgUuid, initCcc, sizeof(uint16_t), sizeof(uint16_t),
                      ATTS_SET_CCC, HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE);
  AttsDynAddAttrConst(pSHdl, attHidRimUuid, hidValIRep3IdMap, sizeof(hidValIRep3IdMap),
                      0, HID_SEC_PERMIT_READ);

  /* HID Output Report */
  AttsDynAddAttrConst(pSHdl, attChUuid, hidORepCh, sizeof(hidORepCh), 0, ATTS_PERMIT_READ);
  AttsDynAddAttr(pSHdl, attHidRepChUuid, NULL, HID_MAX_REPORT_LEN, HID_MAX_REPORT_LEN,
      ATTS_SET_WRITE_CBACK | ATTS_SET_VARIABLE_LEN, HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE);
  AttsDynAddAttrConst(pSHdl, attHidRimUuid, hidValORepIdMap, sizeof(hidValORepIdMap), 
                      0, HID_SEC_PERMIT_READ);

  /* HID Feature Report */
  AttsDynAddAttrConst(pSHdl, attChUuid, hidFRepCh, sizeof(hidFRepCh), 0, ATTS_PERMIT_READ);
  AttsDynAddAttr(pSHdl, attHidRepChUuid, NULL, HID_MAX_REPORT_LEN, HID_MAX_REPORT_LEN,
      ATTS_SET_WRITE_CBACK | ATTS_SET_VARIABLE_LEN, HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE);
  AttsDynAddAttrConst(pSHdl, attHidRimUuid, hidValFRepIdMap, sizeof(hidValFRepIdMap), 
                      0, HID_SEC_PERMIT_READ);

  /* HID Protocol Mode */
  AttsDynAddAttrConst(pSHdl, attChUuid, hidPmCh, sizeof(hidPmCh), 0, ATTS_PERMIT_READ);
  AttsDynAddAttr(pSHdl, attHidRepChUuid, hidPmVal, sizeof(hidPmVal),  sizeof(hidPmVal), 
                      ATTS_SET_WRITE_CBACK, HID_SEC_PERMIT_READ | HID_SEC_PERMIT_WRITE);

  return pSHdl;
}
#endif
