/**
 ****************************************************************************************
 * @addtogroup GLPSTASK
 * @{
 ****************************************************************************************
 */

/*
 * INCLUDE FILES
 ****************************************************************************************
 */

#include "rwip_config.h"

#if (BLE_GL_SENSOR)

#include "gap.h"
#include "gattc_task.h"
#include "glps.h"
#include "glps_task.h"
#include "prf_utils.h"

#include "co_utils.h"
#include "ke_mem.h"

/*
 *  GLUCOSE PROFILE ATTRIBUTES
 ****************************************************************************************
 */

/*
 * LOCAL FUNCTIONS DEFINITIONS
 ****************************************************************************************
 */

/**
 ****************************************************************************************
 * @brief Handles reception of the @ref GLPS_ENABLE_REQ message.
 * The handler enables the Glucose Sensor Profile and initialize readable
 *values.
 * @param[in] msgid Id of the message received (probably unused).off
 * @param[in] param Pointer to the parameters of the message.
 * @param[in] dest_id ID of the receiving task instance (probably unused).
 * @param[in] src_id ID of the sending task instance.
 * @return If the message was consumed or not.
 ****************************************************************************************
 */
__STATIC int glps_enable_req_handler(ke_msg_id_t const msgid,
                                     struct glps_enable_req const *param,
                                     ke_task_id_t const dest_id,
                                     ke_task_id_t const src_id) {
  uint8_t state = ke_state_get(dest_id);
  uint8_t status = PRF_ERR_REQ_DISALLOWED;
  struct glps_enable_rsp *cmp_evt;

  if (state == GLPS_IDLE) {
    uint8_t conidx = KE_IDX_GET(dest_id);
    // Get the address of the environment
    struct glps_env_tag *glps_env = PRF_ENV_GET(GLPS, glps);
    if (!GLPS_IS(conidx, BOND_DATA_PRESENT)) {
      GLPS_SET(conidx, BOND_DATA_PRESENT);
      status = GAP_ERR_NO_ERROR;
      glps_env->env[conidx]->evt_cfg = param->evt_cfg;
    }
  }

  // send completed information to APP task that contains error status
  cmp_evt = KE_MSG_ALLOC(GLPS_ENABLE_RSP, src_id, dest_id, glps_enable_rsp);
  cmp_evt->status = status;
  ke_msg_send(cmp_evt);

  return (KE_MSG_CONSUMED);
}

/**
 ****************************************************************************************
 * @brief Handles reception of the @ref GLPS_MEAS_SEND_REQ message.
 * @param[in] msgid Id of the message received (probably unused).
 * @param[in] param Pointer to the parameters of the message.
 * @param[in] dest_id ID of the receiving task instance (probably unused).
 * @param[in] src_id ID of the sending task instance.
 * @return If the message was consumed or not.
 ****************************************************************************************
 */
__STATIC int glps_meas_send_req_handler(
    ke_msg_id_t const msgid, struct glps_send_meas_with_ctx_cmd const *param,
    ke_task_id_t const dest_id, ke_task_id_t const src_id) {
  uint8_t conidx = KE_IDX_GET(dest_id);
  uint8_t state = ke_state_get(dest_id);
  uint8_t status = PRF_ERR_REQ_DISALLOWED;

  if (state == GLPS_IDLE) {
    // Get the address of the environment
    struct glps_env_tag *glps_env = PRF_ENV_GET(GLPS, glps);

    // Cannot send another measurement in parallel
    if (!GLPS_IS(conidx, SENDING_MEAS)) {
      // inform that device is sending a measurement
      GLPS_SET(conidx, SENDING_MEAS);

      // check if context is supported
      if ((msgid == GLPS_SEND_MEAS_WITH_CTX_CMD) &&
          !(glps_env->meas_ctx_supported)) {
        // Context not supported
        status = (PRF_ERR_FEATURE_NOT_SUPPORTED);
      }
      // check if notifications enabled
      else if (((glps_env->env[conidx]->evt_cfg & GLPS_MEAS_NTF_CFG) == 0) ||
               (((glps_env->env[conidx]->evt_cfg & GLPS_MEAS_CTX_NTF_CFG) ==
                 0) &&
                (msgid == GLPS_SEND_MEAS_WITH_CTX_CMD))) {
        // Not allowed to send measurement if Notifications not enabled.
        status = (PRF_ERR_NTF_DISABLED);
      } else {
        // Allocate the GATT notification message
        struct gattc_send_evt_cmd *meas_val = KE_MSG_ALLOC_DYN(
            GATTC_SEND_EVT_CMD, KE_BUILD_ID(TASK_GATTC, conidx), dest_id,
            gattc_send_evt_cmd, GLP_MEAS_MAX_LEN);

        // Fill in the parameter structure
        meas_val->operation = GATTC_NOTIFY;
        meas_val->handle = GLPS_HANDLE(GLS_IDX_MEAS_VAL);
        // pack measured value in database
        meas_val->length = glps_pack_meas_value(meas_val->value, &(param->meas),
                                                param->seq_num);

        // Measurement value notification not yet sent
        GLPS_CLEAR(conidx, MEAS_SENT);

        // Send the event
        ke_msg_send(meas_val);

        if (msgid == GLPS_SEND_MEAS_WITH_CTX_CMD) {
          // Allocate the GATT notification message
          struct gattc_send_evt_cmd *meas_ctx_val = KE_MSG_ALLOC_DYN(
              GATTC_SEND_EVT_CMD, KE_BUILD_ID(TASK_GATTC, conidx), dest_id,
              gattc_send_evt_cmd, GLP_MEAS_CTX_MAX_LEN);

          // Fill in the parameter structure
          meas_ctx_val->operation = GATTC_NOTIFY;
          meas_ctx_val->handle = GLPS_HANDLE(GLS_IDX_MEAS_CTX_VAL);
          // pack measured value in database
          meas_ctx_val->length = glps_pack_meas_ctx_value(
              meas_ctx_val->value, &(param->ctx), param->seq_num);

          // 2 notification complete messages expected
          GLPS_SET(conidx, MEAS_CTX_SENT);

          // Send the event
          ke_msg_send(meas_ctx_val);
        } else {
          // 1 notification complete messages expected
          GLPS_CLEAR(conidx, MEAS_CTX_SENT);
        }

        status = (GAP_ERR_NO_ERROR);
      }
    }
  }

  // send command complete if an error occurs
  if (status != GAP_ERR_NO_ERROR) {
    // send completed information to APP task that contains error status
    struct glps_cmp_evt *cmp_evt =
        KE_MSG_ALLOC(GLPS_CMP_EVT, src_id, dest_id, glps_cmp_evt);

    cmp_evt->request = GLPS_SEND_MEAS_REQ_NTF_CMP;
    cmp_evt->status = status;

    ke_msg_send(cmp_evt);
  }

  return (KE_MSG_CONSUMED);
}

/**
 ****************************************************************************************
 * @brief Handles reception of the @ref GLPS_SEND_RACP_RSP_CMD message.
 * Send when a RACP requests is finished
 *
 * @param[in] msgid Id of the message received (probably unused).
 * @param[in] param Pointer to the parameters of the message.
 * @param[in] dest_id ID of the receiving task instance (probably unused).
 * @param[in] src_id ID of the sending task instance.
 * @return If the message was consumed or not.
 ****************************************************************************************
 */
__STATIC int glps_send_racp_rsp_cmd_handler(
    ke_msg_id_t const msgid, struct glps_send_racp_rsp_cmd const *param,
    ke_task_id_t const dest_id, ke_task_id_t const src_id) {
  // Status
  uint8_t status = PRF_ERR_REQ_DISALLOWED;
  uint8_t conidx = KE_IDX_GET(dest_id);
  uint8_t state = ke_state_get(dest_id);

  if (state == GLPS_IDLE) {
    // Get the address of the environment
    struct glps_env_tag *glps_env = PRF_ENV_GET(GLPS, glps);

    // check if op code valid
    if ((param->op_code < GLP_REQ_REP_STRD_RECS) ||
        (param->op_code > GLP_REQ_REP_NUM_OF_STRD_RECS)) {
      // Wrong op code
      status = PRF_ERR_INVALID_PARAM;
    }
    // check if RACP on going
    else if ((param->op_code != GLP_REQ_ABORT_OP) &&
             !(GLPS_IS(conidx, RACP_ON_GOING))) {
      // Cannot send response since no RACP on going
      status = PRF_ERR_REQ_DISALLOWED;
    }
    // Indication not enabled on peer device
    else if ((glps_env->env[conidx]->evt_cfg & GLPS_RACP_IND_CFG) == 0) {
      status = PRF_ERR_IND_DISABLED;
      // There is no more RACP on going
      GLPS_CLEAR(conidx, RACP_ON_GOING);
    } else {
      struct glp_racp_rsp racp_rsp;
      // Allocate the GATT indication message
      struct gattc_send_evt_cmd *racp_rsp_val = KE_MSG_ALLOC_DYN(
          GATTC_SEND_EVT_CMD, KE_BUILD_ID(TASK_GATTC, conidx), dest_id,
          gattc_send_evt_cmd, GLP_REC_ACCESS_CTRL_MAX_LEN);

      // Fill in the parameter structure
      racp_rsp_val->operation = GATTC_INDICATE;
      racp_rsp_val->handle = GLPS_HANDLE(GLS_IDX_REC_ACCESS_CTRL_VAL);

      // Number of stored record calculation succeed.
      if ((param->op_code == GLP_REQ_REP_NUM_OF_STRD_RECS) &&
          (param->status == GLP_RSP_SUCCESS)) {
        racp_rsp.op_code = GLP_REQ_NUM_OF_STRD_RECS_RSP;
        racp_rsp.operand.num_of_record = param->num_of_record;
      }
      // Send back status information
      else {
        racp_rsp.op_code = GLP_REQ_RSP_CODE;
        racp_rsp.operand.rsp.op_code_req = param->op_code;
        racp_rsp.operand.rsp.status = param->status;
      }

      // pack measured value in database
      racp_rsp_val->length = glps_pack_racp_rsp(racp_rsp_val->value, &racp_rsp);

      // There is no more RACP on going
      GLPS_CLEAR(conidx, RACP_ON_GOING);
      status = GAP_ERR_NO_ERROR;

      // Store that response sent by application
      GLPS_SET(conidx, RACP_RSP_SENT_BY_APP);

      // send RACP Response indication
      ke_msg_send(racp_rsp_val);
    }
  }

  if (status != GAP_ERR_NO_ERROR) {
    // send completed information about request failed
    struct glps_cmp_evt *cmp_evt =
        KE_MSG_ALLOC(GLPS_CMP_EVT, src_id, dest_id, glps_cmp_evt);
    cmp_evt->request = GLPS_SEND_RACP_RSP_IND_CMP;
    cmp_evt->status = status;
    ke_msg_send(cmp_evt);
  }
  return (KE_MSG_CONSUMED);
}

/**
 ****************************************************************************************
 * @brief Handles reception of the attribute info request message.
 *
 * @param[in] msgid Id of the message received (probably unused).
 * @param[in] param Pointer to the parameters of the message.
 * @param[in] dest_id ID of the receiving task instance (probably unused).
 * @param[in] src_id ID of the sending task instance.
 * @return If the message was consumed or not.
 ****************************************************************************************
 */
__STATIC int gattc_att_info_req_ind_handler(
    ke_msg_id_t const msgid, struct gattc_att_info_req_ind *param,
    ke_task_id_t const dest_id, ke_task_id_t const src_id) {
  uint8_t state = ke_state_get(dest_id);

  if (state == GLPS_IDLE) {
    struct glps_env_tag *glps_env = PRF_ENV_GET(GLPS, glps);
    uint8_t att_idx = GLPS_IDX(param->handle);
    struct gattc_att_info_cfm *cfm;

    // Send write response
    cfm = KE_MSG_ALLOC(GATTC_ATT_INFO_CFM, src_id, dest_id, gattc_att_info_cfm);
    cfm->handle = param->handle;

    // check if it's a client configuration char
    if ((att_idx == GLS_IDX_MEAS_NTF_CFG) ||
        (att_idx == GLS_IDX_MEAS_CTX_NTF_CFG) ||
        (att_idx == GLS_IDX_REC_ACCESS_CTRL_IND_CFG)) {
      // CCC attribute length = 2
      cfm->length = 2;
      cfm->status = GAP_ERR_NO_ERROR;
    } else if (att_idx == GLS_IDX_REC_ACCESS_CTRL_VAL) {
      // force length to zero to reject any write starting from something != 0
      cfm->length = 0;
      cfm->status = GAP_ERR_NO_ERROR;
    }
    // not expected request
    else {
      cfm->length = 0;
      cfm->status = ATT_ERR_WRITE_NOT_PERMITTED;
    }
    ke_msg_send(cfm);
  }

  return (KE_MSG_CONSUMED);
}

/**
 ****************************************************************************************
 * @brief Handles reception of the @ref GATT_CODE_ATT_WR_CMD_IND message.
 * The handler compares the new values with current ones and notifies them if
 *they changed.
 * @param[in] msgid Id of the message received (probably unused).
 * @param[in] param Pointer to the parameters of the message.
 * @param[in] dest_id ID of the receiving task instance (probably unused).
 * @param[in] src_id ID of the sending task instance.
 * @return If the message was consumed or not.
 ****************************************************************************************
 */
__STATIC int gattc_write_req_ind_handler(ke_msg_id_t const msgid,
                                         struct gattc_write_req_ind *param,
                                         ke_task_id_t const dest_id,
                                         ke_task_id_t const src_id) {
  uint8_t state = ke_state_get(dest_id);
  struct glp_racp_rsp racp_rsp;
  racp_rsp.op_code = 0;

  if (state == GLPS_IDLE) {
    uint8_t status = GAP_ERR_NO_ERROR;
    struct gattc_write_cfm *cfm;
    uint8_t conidx = KE_IDX_GET(dest_id);
    // Get the address of the environment
    struct glps_env_tag *glps_env = PRF_ENV_GET(GLPS, glps);
    uint8_t att_idx = GLPS_IDX(param->handle);

    if (param->offset != 0) {
      status = ATT_ERR_UNLIKELY_ERR;
    }
    // check if it's a client configuration char
    else if ((att_idx == GLS_IDX_MEAS_NTF_CFG) ||
             (att_idx == GLS_IDX_MEAS_CTX_NTF_CFG) ||
             (att_idx == GLS_IDX_REC_ACCESS_CTRL_IND_CFG)) {
      uint16_t cli_cfg;
      uint8_t evt_mask = GLPS_IND_NTF_EVT(att_idx);

      // get client configuration
      cli_cfg = co_read16(&(param->value));

      // stop indication/notification
      if (cli_cfg == PRF_CLI_STOP_NTFIND) {
        glps_env->env[conidx]->evt_cfg &= ~evt_mask;
      }
      // start indication/notification (check that char value accept it)
      else if (((att_idx == GLS_IDX_REC_ACCESS_CTRL_IND_CFG) &&
                (cli_cfg == PRF_CLI_START_IND)) ||
               ((att_idx != GLS_IDX_REC_ACCESS_CTRL_IND_CFG) &&
                (cli_cfg == PRF_CLI_START_NTF))) {
        glps_env->env[conidx]->evt_cfg |= evt_mask;
      }
      // improper value
      else {
        status = GLP_ERR_IMPROPER_CLI_CHAR_CFG;
      }

      if (status == GAP_ERR_NO_ERROR) {
        // Inform APP of configuration change
        struct glps_cfg_indntf_ind *ind = KE_MSG_ALLOC(
            GLPS_CFG_INDNTF_IND, prf_dst_task_get(&(glps_env->prf_env), conidx),
            dest_id, glps_cfg_indntf_ind);
        ind->evt_cfg = glps_env->env[conidx]->evt_cfg;
        ke_msg_send(ind);
      }
    }

    else if (att_idx == GLS_IDX_REC_ACCESS_CTRL_VAL) {
      if ((glps_env->env[conidx]->evt_cfg & GLPS_RACP_IND_CFG) == 0) {
        // do nothing since indication not enabled for this characteristic
        status = GLP_ERR_IMPROPER_CLI_CHAR_CFG;
      }
      // If a request is on going
      else if (GLPS_IS(conidx, RACP_ON_GOING)) {
        // if it's an abort command, execute it.
        if ((param->offset == 0) && (param->value[0] == GLP_REQ_ABORT_OP)) {
          // forward abort operation to application
          struct glps_racp_req_rcv_ind *req =
              KE_MSG_ALLOC(GLPS_RACP_REQ_RCV_IND,
                           prf_dst_task_get(&(glps_env->prf_env), conidx),
                           dest_id, glps_racp_req_rcv_ind);
          req->racp_req.op_code = GLP_REQ_ABORT_OP;
          req->racp_req.filter.operator= 0;
          ke_msg_send(req);
        } else {
          // do nothing since a procedure already in progress
          status = GLP_ERR_PROC_ALREADY_IN_PROGRESS;
        }
      } else {
        struct glp_racp_req racp_req;
        // unpack record access control point value
        uint8_t reqstatus =
            glps_unpack_racp_req(param->value, param->length, &racp_req);

        // check unpacked status
        switch (reqstatus) {
        case PRF_APP_ERROR: {
          /* Request failed */
          status = ATT_ERR_UNLIKELY_ERR;
        } break;
        case GAP_ERR_NO_ERROR: {
          // check wich request shall be send to api task
          switch (racp_req.op_code) {
          case GLP_REQ_REP_STRD_RECS:
          case GLP_REQ_DEL_STRD_RECS:
          case GLP_REQ_REP_NUM_OF_STRD_RECS: {
            // forward request operation to application
            struct glps_racp_req_rcv_ind *req =
                KE_MSG_ALLOC(GLPS_RACP_REQ_RCV_IND,
                             prf_dst_task_get(&(glps_env->prf_env), conidx),
                             dest_id, glps_racp_req_rcv_ind);
            req->racp_req = racp_req;
            // RACP on going.
            GLPS_SET(conidx, RACP_ON_GOING);
            ke_msg_send(req);
          } break;
          case GLP_REQ_ABORT_OP: {
            // nothing to abort, send an error message.
            racp_rsp.op_code = GLP_REQ_RSP_CODE;
            racp_rsp.operand.rsp.op_code_req = racp_req.op_code;
            racp_rsp.operand.rsp.status = GLP_RSP_ABORT_UNSUCCESSFUL;
          } break;
          default: {
            // nothing to do since it's handled during unpack
          } break;
          }
        } break;
        default: {
          /* There is an error in record access control request, inform peer
           * device that request is incorrect. */
          racp_rsp.op_code = GLP_REQ_RSP_CODE;
          racp_rsp.operand.rsp.op_code_req = racp_req.op_code;
          racp_rsp.operand.rsp.status = reqstatus;
        } break;
        }
      }
    }
    // not expected request
    else {
      status = ATT_ERR_WRITE_NOT_PERMITTED;
    }

    // Send write response
    cfm = KE_MSG_ALLOC(GATTC_WRITE_CFM, src_id, dest_id, gattc_write_cfm);
    cfm->handle = param->handle;
    cfm->status = status;
    ke_msg_send(cfm);

    /* The racp response has to be sent - after write confirm */
    if (racp_rsp.op_code != 0) {
      // Allocate the GATT indication message
      struct gattc_send_evt_cmd *racp_rsp_val = KE_MSG_ALLOC_DYN(
          GATTC_SEND_EVT_CMD, KE_BUILD_ID(TASK_GATTC, conidx), dest_id,
          gattc_send_evt_cmd, GLP_REC_ACCESS_CTRL_MAX_LEN);

      racp_rsp_val->operation = GATTC_INDICATE;
      racp_rsp_val->handle = param->handle;
      // pack measured value in database
      racp_rsp_val->length = glps_pack_racp_rsp(racp_rsp_val->value, &racp_rsp);

      // Store that response internally sent by profile
      GLPS_CLEAR(conidx, RACP_RSP_SENT_BY_APP);

      // send RACP Response indication
      ke_msg_send(racp_rsp_val);
    }
  }

  return (KE_MSG_CONSUMED);
}

/**
 ****************************************************************************************
 * @brief Handles reception of the read request from peer device
 *
 * @param[in] msgid Id of the message received (probably unused).
 * @param[in] param Pointer to the parameters of the message.
 * @param[in] dest_id ID of the receiving task instance (probably unused).
 * @param[in] src_id ID of the sending task instance.
 * @return If the message was consumed or not.
 ****************************************************************************************
 */
__STATIC int gattc_read_req_ind_handler(ke_msg_id_t const msgid,
                                        struct gattc_read_req_ind const *param,
                                        ke_task_id_t const dest_id,
                                        ke_task_id_t const src_id) {
  ke_state_t state = ke_state_get(dest_id);

  if (state == GLPS_IDLE) {
    // Send value to peer device.
    struct gattc_read_cfm *cfm = KE_MSG_ALLOC_DYN(
        GATTC_READ_CFM, src_id, dest_id, gattc_read_cfm, sizeof(uint16_t));
    cfm->handle = param->handle;
    cfm->status = ATT_ERR_NO_ERROR;
    cfm->length = sizeof(uint16_t);

    // Get the address of the environment
    struct glps_env_tag *glps_env = PRF_ENV_GET(GLPS, glps);
    uint8_t att_idx = GLPS_IDX(param->handle);
    uint8_t conidx = KE_IDX_GET(dest_id);

    switch (att_idx) {
    case GLS_IDX_MEAS_NTF_CFG: {
      co_write16p(cfm->value,
                  (glps_env->env[conidx]->evt_cfg & GLPS_MEAS_NTF_CFG)
                      ? PRF_CLI_START_NTF
                      : PRF_CLI_STOP_NTFIND);
    } break;
    case GLS_IDX_MEAS_CTX_NTF_CFG: {
      co_write16p(cfm->value,
                  (glps_env->env[conidx]->evt_cfg & GLPS_MEAS_CTX_NTF_CFG)
                      ? PRF_CLI_START_NTF
                      : PRF_CLI_STOP_NTFIND);
    } break;
    case GLS_IDX_REC_ACCESS_CTRL_IND_CFG: {
      co_write16p(cfm->value,
                  (glps_env->env[conidx]->evt_cfg & GLPS_RACP_IND_CFG)
                      ? PRF_CLI_START_IND
                      : PRF_CLI_STOP_NTFIND);
    } break;
    case GLS_IDX_FEATURE_VAL: {
      co_write16p(cfm->value, glps_env->features);
    } break;
    default: {
      cfm->status = ATT_ERR_INSUFF_AUTHOR;
    } break;
    }

    ke_msg_send(cfm);
  }

  return (KE_MSG_CONSUMED);
}

/**
 ****************************************************************************************
 * @brief Handles @ref GATTC_CMP_EVT for GATTC_NOTIFY and GATT_INDICATE message
 *meaning that Measurement notification/indication has been correctly sent to
 *peer device
 *
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance
 * @param[in] src_id    ID of the sending task instance.
 * @return If the message was consumed or not.
 ****************************************************************************************
 */
__STATIC int gattc_cmp_evt_handler(ke_msg_id_t const msgid,
                                   struct gattc_cmp_evt const *param,
                                   ke_task_id_t const dest_id,
                                   ke_task_id_t const src_id) {
  uint8_t conidx = KE_IDX_GET(dest_id);
  uint8_t state = ke_state_get(dest_id);

  if (state == GLPS_IDLE) {
    // Get the address of the environment
    struct glps_env_tag *glps_env = PRF_ENV_GET(GLPS, glps);

    switch (param->operation) {
    case GATTC_NOTIFY: {
      /* send message indication if an error occurs,
       * or if all notification complete event has been received
       */
      if ((param->status != GAP_ERR_NO_ERROR) ||
          (!(GLPS_IS(conidx, MEAS_CTX_SENT))) ||
          (GLPS_IS(conidx, MEAS_CTX_SENT) && (GLPS_IS(conidx, MEAS_SENT)))) {
        GLPS_CLEAR(conidx, SENDING_MEAS);

        // send completed information to APP task
        struct glps_cmp_evt *cmp_evt = KE_MSG_ALLOC(
            GLPS_CMP_EVT, prf_dst_task_get(&(glps_env->prf_env), conidx),
            dest_id, glps_cmp_evt);

        cmp_evt->request = GLPS_SEND_MEAS_REQ_NTF_CMP;
        cmp_evt->status = param->status;

        ke_msg_send(cmp_evt);
      } else {
        // Measurement value notification sent
        GLPS_SET(conidx, MEAS_SENT);
      }
    } break;
    case GATTC_INDICATE: {
      // verify if indication should be conveyed to application task
      if (GLPS_IS(conidx, RACP_RSP_SENT_BY_APP)) {
        // send completed information to APP task
        struct glps_cmp_evt *cmp_evt = KE_MSG_ALLOC(
            GLPS_CMP_EVT, prf_dst_task_get(&(glps_env->prf_env), conidx),
            dest_id, glps_cmp_evt);

        cmp_evt->request = GLPS_SEND_RACP_RSP_IND_CMP;
        cmp_evt->status = param->status;

        ke_msg_send(cmp_evt);
      }

      GLPS_CLEAR(conidx, RACP_RSP_SENT_BY_APP);
    } break;

    default:
      break;
    }
  }

  return (KE_MSG_CONSUMED);
}

/*
 * GLOBAL VARIABLE DEFINITIONS
 ****************************************************************************************
 */

/// Default State handlers definition
KE_MSG_HANDLER_TAB(glps){
    {GLPS_ENABLE_REQ, (ke_msg_func_t)glps_enable_req_handler},
    {GATTC_ATT_INFO_REQ_IND, (ke_msg_func_t)gattc_att_info_req_ind_handler},
    {GATTC_WRITE_REQ_IND, (ke_msg_func_t)gattc_write_req_ind_handler},
    {GATTC_READ_REQ_IND, (ke_msg_func_t)gattc_read_req_ind_handler},
    {GLPS_SEND_MEAS_WITH_CTX_CMD, (ke_msg_func_t)glps_meas_send_req_handler},
    {GLPS_SEND_MEAS_WITHOUT_CTX_CMD, (ke_msg_func_t)glps_meas_send_req_handler},
    {GLPS_SEND_RACP_RSP_CMD, (ke_msg_func_t)glps_send_racp_rsp_cmd_handler},
    {GATTC_CMP_EVT, (ke_msg_func_t)gattc_cmp_evt_handler},
};

void glps_task_init(struct ke_task_desc *task_desc) {
  // Get the address of the environment
  struct glps_env_tag *glps_env = PRF_ENV_GET(GLPS, glps);

  task_desc->msg_handler_tab = glps_msg_handler_tab;
  task_desc->msg_cnt = ARRAY_LEN(glps_msg_handler_tab);
  task_desc->state = glps_env->state;
  task_desc->idx_max = GLPS_IDX_MAX;
}

#endif /* #if (BLE_GL_SENSOR) */

/// @} GLPSTASK
