/******************************************************************************
 *
 *  Copyright (C) 2010-2014 Broadcom Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

/******************************************************************************
 *
 *  NFA interface for device management
 *
 ******************************************************************************/
#include <string.h>

#include <android-base/stringprintf.h>
#include <base/logging.h>

#include "ndef_utils.h"
#include "nfa_api.h"
#include "nfa_ce_int.h"

using android::base::StringPrintf;

extern bool nfc_debug_enabled;

/*****************************************************************************
**  Constants
*****************************************************************************/

/*****************************************************************************
**  APIs
*****************************************************************************/
/*******************************************************************************
**
** Function         NFA_Init
**
** Description      This function initializes control blocks for NFA
**
**                  p_hal_entry_tbl points to a table of HAL entry points
**
**                  NOTE: the buffer that p_hal_entry_tbl points must be
**                  persistent until NFA is disabled.
**
** Returns          none
**
*******************************************************************************/
void NFA_Init(tHAL_NFC_ENTRY* p_hal_entry_tbl) {
  DLOG_IF(INFO, nfc_debug_enabled) << __func__;
  nfa_sys_init();
  nfa_dm_init();
  nfa_p2p_init();
  nfa_snep_init(false);
  nfa_rw_init();
  nfa_ce_init();
  nfa_ee_init();
  if (nfa_ee_max_ee_cfg != 0) {
    nfa_dm_cb.get_max_ee = p_hal_entry_tbl->get_max_ee;
    nfa_hci_init();
  }

  /* Initialize NFC module */
  NFC_Init(p_hal_entry_tbl);
}

/*******************************************************************************
**
** Function         NFA_Enable
**
** Description      This function enables NFC. Prior to calling NFA_Enable,
**                  the NFCC must be powered up, and ready to receive commands.
**                  This function enables the tasks needed by NFC, opens the NCI
**                  transport, resets the NFC controller, downloads patches to
**                  the NFCC (if necessary), and initializes the NFC subsystems.
**
**                  This function should only be called once - typically when
**                  NFC is enabled during boot-up, or when NFC is enabled from a
**                  settings UI. Subsequent calls to NFA_Enable while NFA is
**                  enabling or enabled will be ignored. When the NFC startup
**                  procedure is completed, an NFA_DM_ENABLE_EVT is returned to
**                  the application using the tNFA_DM_CBACK.
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_Enable(tNFA_DM_CBACK* p_dm_cback,
                       tNFA_CONN_CBACK* p_conn_cback) {
  tNFA_DM_API_ENABLE* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  /* Validate parameters */
  if ((!p_dm_cback) || (!p_conn_cback)) {
    LOG(ERROR) << StringPrintf("error null callback");
    return (NFA_STATUS_FAILED);
  }

  p_msg = (tNFA_DM_API_ENABLE*)GKI_getbuf(sizeof(tNFA_DM_API_ENABLE));
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_ENABLE_EVT;
    p_msg->p_dm_cback = p_dm_cback;
    p_msg->p_conn_cback = p_conn_cback;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_Disable
**
** Description      This function is called to shutdown NFC. The tasks for NFC
**                  are terminated, and clean up routines are performed. This
**                  function is typically called during platform shut-down, or
**                  when NFC is disabled from a settings UI. When the NFC
**                  shutdown procedure is completed, an NFA_DM_DISABLE_EVT is
**                  returned to the application using the tNFA_DM_CBACK.
**
**                  The platform should wait until the NFC_DISABLE_REVT is
**                  received before powering down the NFC chip and NCI
**                  transport. This is required to so that NFA can gracefully
**                  shut down any open connections.
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_Disable(bool graceful) {
  tNFA_DM_API_DISABLE* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("NFA_Disable (graceful=%i)", graceful);

  p_msg = (tNFA_DM_API_DISABLE*)GKI_getbuf(sizeof(tNFA_DM_API_DISABLE));
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_DISABLE_EVT;
    p_msg->graceful = graceful;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_GetNCIVersion
**
** Description      Returns the NCI version of the NFCC to upper layer
**
**
** Returns          NCI version NCI2.0 / NCI1.0
**
*******************************************************************************/
uint8_t NFA_GetNCIVersion() { return NFC_GetNCIVersion(); }

/*******************************************************************************
**
** Function         NFA_SetPowerSubStateForScreenState
**
** Description      Update the power sub-state as per current screen state to
**                  NFCC.
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_SetPowerSubStateForScreenState(uint8_t screenState) {
  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("%s: state:0x%X", __func__, screenState);

  uint8_t nci_scren_state = 0xFF;
  uint16_t buf_size = sizeof(tNFA_DM_API_SET_POWER_SUB_STATE);
  tNFA_DM_API_SET_POWER_SUB_STATE* p_msg =
      (tNFA_DM_API_SET_POWER_SUB_STATE*)GKI_getbuf(buf_size);

  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_SET_POWER_SUB_STATE_EVT;
    switch (screenState) {
      case NFA_SCREEN_STATE_ON_UNLOCKED:
        nci_scren_state = SCREEN_STATE_ON_UNLOCKED;
        break;
      case NFA_SCREEN_STATE_OFF_UNLOCKED:
        nci_scren_state = SCREEN_STATE_OFF_UNLOCKED;
        break;
      case NFA_SCREEN_STATE_ON_LOCKED:
        nci_scren_state = SCREEN_STATE_ON_LOCKED;
        break;
      case NFA_SCREEN_STATE_OFF_LOCKED:
        nci_scren_state = SCREEN_STATE_OFF_LOCKED;
        break;

      default:
        DLOG_IF(INFO, nfc_debug_enabled)
            << StringPrintf("%s, unknown screen state", __func__);
        break;
    }

    p_msg->screen_state = nci_scren_state;

    nfa_sys_sendmsg(p_msg);
    return (NFA_STATUS_OK);
  }
  return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function         NFA_SetConfig
**
** Description      Set the configuration parameters to NFCC. The result is
**                  reported with an NFA_DM_SET_CONFIG_EVT in the tNFA_DM_CBACK
**                  callback.
**
** Note:            If RF discovery is started,
**                  NFA_StopRfDiscovery()/NFA_RF_DISCOVERY_STOPPED_EVT should
**                  happen before calling this function. Most Configuration
**                  parameters are related to RF discovery.
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_BUSY if previous setting is on-going
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_SetConfig(tNFA_PMID param_id, uint8_t length, uint8_t* p_data) {
  tNFA_DM_API_SET_CONFIG* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("param_id:0x%X", param_id);

  p_msg = (tNFA_DM_API_SET_CONFIG*)GKI_getbuf(
      (uint16_t)(sizeof(tNFA_DM_API_SET_CONFIG) + length));
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_SET_CONFIG_EVT;

    p_msg->param_id = param_id;
    p_msg->length = length;
    p_msg->p_data = (uint8_t*)(p_msg + 1);

    /* Copy parameter data */
    memcpy(p_msg->p_data, p_data, length);

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_GetConfig
**
** Description      Get the configuration parameters from NFCC. The result is
**                  reported with an NFA_DM_GET_CONFIG_EVT in the tNFA_DM_CBACK
**                  callback.
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_GetConfig(uint8_t num_ids, tNFA_PMID* p_param_ids) {
  tNFA_DM_API_GET_CONFIG* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("num_ids: %i", num_ids);

  p_msg = (tNFA_DM_API_GET_CONFIG*)GKI_getbuf(
      (uint16_t)(sizeof(tNFA_DM_API_GET_CONFIG) + num_ids));
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_GET_CONFIG_EVT;

    p_msg->num_ids = num_ids;
    p_msg->p_pmids = (tNFA_PMID*)(p_msg + 1);

    /* Copy the param IDs */
    memcpy(p_msg->p_pmids, p_param_ids, num_ids);

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_RequestExclusiveRfControl
**
** Description      Request exclusive control of NFC.
**                  - Previous behavior (polling/tag reading, DH card emulation)
**                    will be suspended .
**                  - Polling and listening will be done based on the specified
**                    params
**
**                  The NFA_EXCLUSIVE_RF_CONTROL_STARTED_EVT event of
**                  tNFA_CONN_CBACK indicates the status of the operation.
**
**                  NFA_ACTIVATED_EVT and NFA_DEACTIVATED_EVT indicates link
**                  activation/deactivation.
**
**                  NFA_SendRawFrame is used to send data to the peer.
**                  NFA_DATA_EVT indicates data from the peer.
**
**                  If a tag is activated, then the NFA_RW APIs may be used to
**                  send commands to the tag. Incoming NDEF messages are sent to
**                  the NDEF callback.
**
**                  Once exclusive RF control has started, NFA will not activate
**                  LLCP internally. The application has exclusive control of
**                  the link.
**
** Note:            If RF discovery is started,
**                  NFA_StopRfDiscovery()/NFA_RF_DISCOVERY_STOPPED_EVT should
**                  happen before calling this function
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_RequestExclusiveRfControl(tNFA_TECHNOLOGY_MASK poll_mask,
                                          tNFA_LISTEN_CFG* p_listen_cfg,
                                          tNFA_CONN_CBACK* p_conn_cback,
                                          tNFA_NDEF_CBACK* p_ndef_cback) {
  tNFA_DM_API_REQ_EXCL_RF_CTRL* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("poll_mask=0x%x", poll_mask);

  if (!p_conn_cback) {
    LOG(ERROR) << StringPrintf("error null callback");
    return (NFA_STATUS_FAILED);
  }

  p_msg = (tNFA_DM_API_REQ_EXCL_RF_CTRL*)GKI_getbuf(
      sizeof(tNFA_DM_API_REQ_EXCL_RF_CTRL));
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_REQUEST_EXCL_RF_CTRL_EVT;
    p_msg->poll_mask = poll_mask;
    p_msg->p_conn_cback = p_conn_cback;
    p_msg->p_ndef_cback = p_ndef_cback;

    if (p_listen_cfg)
      memcpy(&p_msg->listen_cfg, p_listen_cfg, sizeof(tNFA_LISTEN_CFG));
    else
      memset(&p_msg->listen_cfg, 0x00, sizeof(tNFA_LISTEN_CFG));

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_ReleaseExclusiveRfControl
**
** Description      Release exclusive control of NFC. Once released, behavior
**                  prior to obtaining exclusive RF control will resume.
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_ReleaseExclusiveRfControl(void) {
  NFC_HDR* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  if (!nfa_dm_cb.p_excl_conn_cback) {
    LOG(ERROR) << StringPrintf(
        "Exclusive rf control is not in "
        "progress");
    return (NFA_STATUS_FAILED);
  }

  p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR));
  if (p_msg != NULL) {
    p_msg->event = NFA_DM_API_RELEASE_EXCL_RF_CTRL_EVT;
    nfa_sys_sendmsg(p_msg);
    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_EnablePolling
**
** Description      Enable polling for technologies specified by poll_mask.
**
**                  The following events (notified using the connection
**                  callback registered with NFA_Enable) are generated during
**                  polling:
**
**                  - NFA_POLL_ENABLED_EVT indicates whether or not polling
**                    successfully enabled.
**                  - NFA_DISC_RESULT_EVT indicates there are more than one
**                    devices, so application must select one of tags by calling
**                    NFA_Select().
**                  - NFA_SELECT_RESULT_EVT indicates whether previous selection
**                    was successful or not. If it was failed then application
**                    must select again or deactivate by calling
**                    NFA_Deactivate().
**                  - NFA_ACTIVATED_EVT is generated when an NFC link is
**                    activated.
**                  - NFA_NDEF_DETECT_EVT is generated if tag is activated
**                  - NFA_LLCP_ACTIVATED_EVT/NFA_LLCP_DEACTIVATED_EVT is
**                    generated if NFC-DEP is activated
**                  - NFA_DEACTIVATED_EVT will be returned after deactivating
**                    NFC link.
**
** Note:            If RF discovery is started,
**                  NFA_StopRfDiscovery()/NFA_RF_DISCOVERY_STOPPED_EVT should
**                  happen before calling this function
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_EnablePolling(tNFA_TECHNOLOGY_MASK poll_mask) {
  tNFA_DM_API_ENABLE_POLL* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("0x%X", poll_mask);

  p_msg = (tNFA_DM_API_ENABLE_POLL*)GKI_getbuf(sizeof(tNFA_DM_API_ENABLE_POLL));
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_ENABLE_POLLING_EVT;
    p_msg->poll_mask = poll_mask;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_DisablePolling
**
** Description      Disable polling
**                  NFA_POLL_DISABLED_EVT will be returned after stopping
**                  polling.
**
** Note:            If RF discovery is started,
**                  NFA_StopRfDiscovery()/NFA_RF_DISCOVERY_STOPPED_EVT should
**                  happen before calling this function
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_DisablePolling(void) {
  NFC_HDR* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR));
  if (p_msg != NULL) {
    p_msg->event = NFA_DM_API_DISABLE_POLLING_EVT;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_EnableListening
**
** Description      Enable listening.
**                  NFA_LISTEN_ENABLED_EVT will be returned after listening is
**                  allowed.
**
**                  The actual listening technologies are specified by other NFA
**                  API functions. Such functions include (but not limited to)
**                  NFA_CeConfigureUiccListenTech.
**                  If NFA_DisableListening () is called to ignore the listening
**                  technologies, NFA_EnableListening () is called to restore
**                  the listening technologies set by these functions.
**
** Note:            If RF discovery is started,
**                  NFA_StopRfDiscovery()/NFA_RF_DISCOVERY_STOPPED_EVT should
**                  happen before calling this function
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_EnableListening(void) {
  NFC_HDR* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR));
  if (p_msg != NULL) {
    p_msg->event = NFA_DM_API_ENABLE_LISTENING_EVT;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_DisableListening
**
** Description      Disable listening
**                  NFA_LISTEN_DISABLED_EVT will be returned after stopping
**                  listening. This function is called to exclude listen at RF
**                  discovery.
**
** Note:            If RF discovery is started,
**                  NFA_StopRfDiscovery()/NFA_RF_DISCOVERY_STOPPED_EVT should
**                  happen before calling this function
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_DisableListening(void) {
  NFC_HDR* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR));
  if (p_msg != NULL) {
    p_msg->event = NFA_DM_API_DISABLE_LISTENING_EVT;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_PauseP2p
**
** Description      Pause P2P services.
**                  NFA_P2P_PAUSED_EVT will be returned after P2P services are
**                  disabled.
**
**                  The P2P services enabled by NFA_P2p* API functions are not
**                  available. NFA_ResumeP2p() is called to resume the P2P
**                  services.
**
** Note:            If RF discovery is started,
**                  NFA_StopRfDiscovery()/NFA_RF_DISCOVERY_STOPPED_EVT should
**                  happen before calling this function
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_PauseP2p(void) {
  NFC_HDR* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR));
  if (p_msg != NULL) {
    p_msg->event = NFA_DM_API_PAUSE_P2P_EVT;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_ResumeP2p
**
** Description      Resume P2P services.
**                  NFA_P2P_RESUMED_EVT will be returned after P2P services are.
**                  enables again.
**
** Note:            If RF discovery is started,
**                  NFA_StopRfDiscovery()/NFA_RF_DISCOVERY_STOPPED_EVT should
**                  happen before calling this function
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_ResumeP2p(void) {
  NFC_HDR* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR));
  if (p_msg != NULL) {
    p_msg->event = NFA_DM_API_RESUME_P2P_EVT;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_SetP2pListenTech
**
** Description      This function is called to set listen technology for
**                  NFC-DEP. This funtion may be called before or after starting
**                  any server on NFA P2P/CHO/SNEP.
**                  If there is no technology for NFC-DEP, P2P listening will be
**                  stopped.
**
**                  NFA_SET_P2P_LISTEN_TECH_EVT without data will be returned.
**
** Note:            If RF discovery is started,
**                  NFA_StopRfDiscovery()/NFA_RF_DISCOVERY_STOPPED_EVT should
**                  happen before calling this function
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_SetP2pListenTech(tNFA_TECHNOLOGY_MASK tech_mask) {
  tNFA_DM_API_SET_P2P_LISTEN_TECH* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("tech_mask:0x%X", tech_mask);

  p_msg = (tNFA_DM_API_SET_P2P_LISTEN_TECH*)GKI_getbuf(
      sizeof(tNFA_DM_API_SET_P2P_LISTEN_TECH));
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_SET_P2P_LISTEN_TECH_EVT;
    p_msg->tech_mask = tech_mask;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_StartRfDiscovery
**
** Description      Start RF discovery
**                  RF discovery parameters shall be set by other APIs.
**
**                  An NFA_RF_DISCOVERY_STARTED_EVT indicates whether starting
**                  was successful or not.
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_StartRfDiscovery(void) {
  NFC_HDR* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR));
  if (p_msg != NULL) {
    p_msg->event = NFA_DM_API_START_RF_DISCOVERY_EVT;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_StopRfDiscovery
**
** Description      Stop RF discovery
**
**                  An NFA_RF_DISCOVERY_STOPPED_EVT indicates whether stopping
**                  was successful or not.
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_StopRfDiscovery(void) {
  NFC_HDR* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR));
  if (p_msg != NULL) {
    p_msg->event = NFA_DM_API_STOP_RF_DISCOVERY_EVT;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_SetRfDiscoveryDuration
**
** Description      Set the duration of the single discovery period in [ms].
**                  Allowable range: 0 ms to 0xFFFF ms.
**
**                  If discovery is already started, the application should
**                  call NFA_StopRfDiscovery prior to calling
**                  NFA_SetRfDiscoveryDuration, and then call
**                  NFA_StartRfDiscovery afterwards to restart discovery using
**                  the new duration.
**
** Note:            If RF discovery is started,
**                  NFA_StopRfDiscovery()/NFA_RF_DISCOVERY_STOPPED_EVT should
**                  happen before calling this function
**
** Returns:
**                  NFA_STATUS_OK, if command accepted
**                  NFA_STATUS_FAILED: otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_SetRfDiscoveryDuration(uint16_t discovery_period_ms) {
  tNFA_DM_API_SET_RF_DISC_DUR* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  /* Post the API message */
  p_msg = (tNFA_DM_API_SET_RF_DISC_DUR*)GKI_getbuf(sizeof(NFC_HDR));
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_SET_RF_DISC_DURATION_EVT;

    /* Set discovery duration */
    p_msg->rf_disc_dur_ms = discovery_period_ms;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_Select
**
** Description      Select one from detected devices during discovery
**                  (from NFA_DISC_RESULT_EVTs). The application should wait for
**                  the final NFA_DISC_RESULT_EVT before selecting.
**
**                  An NFA_SELECT_RESULT_EVT indicates whether selection was
**                  successful or not. If failed then application must select
**                  again or deactivate by NFA_Deactivate().
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_INVALID_PARAM if RF interface is not matched
**                  protocol
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_Select(uint8_t rf_disc_id, tNFA_NFC_PROTOCOL protocol,
                       tNFA_INTF_TYPE rf_interface) {
  tNFA_DM_API_SELECT* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("rf_disc_id:0x%X, protocol:0x%X, rf_interface:0x%X",
                      rf_disc_id, protocol, rf_interface);

  if (((rf_interface == NFA_INTERFACE_ISO_DEP) &&
       (protocol != NFA_PROTOCOL_ISO_DEP)) ||
      ((rf_interface == NFA_INTERFACE_NFC_DEP) &&
       (protocol != NFA_PROTOCOL_NFC_DEP))) {
    LOG(ERROR) << StringPrintf("RF interface is not matched protocol");
    return (NFA_STATUS_INVALID_PARAM);
  }

  p_msg =
      (tNFA_DM_API_SELECT*)GKI_getbuf((uint16_t)(sizeof(tNFA_DM_API_SELECT)));
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_SELECT_EVT;
    p_msg->rf_disc_id = rf_disc_id;
    p_msg->protocol = protocol;
    p_msg->rf_interface = rf_interface;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_UpdateRFCommParams
**
** Description      This function is called to update RF Communication
**                  parameters once the Frame RF Interface has been activated.
**
**                  An NFA_UPDATE_RF_PARAM_RESULT_EVT indicates whether updating
**                  was successful or not.
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_UpdateRFCommParams(tNFA_RF_COMM_PARAMS* p_params) {
  tNFA_DM_API_UPDATE_RF_PARAMS* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  p_msg = (tNFA_DM_API_UPDATE_RF_PARAMS*)GKI_getbuf(
      (uint16_t)(sizeof(tNFA_DM_API_UPDATE_RF_PARAMS)));
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_UPDATE_RF_PARAMS_EVT;
    memcpy(&p_msg->params, p_params, sizeof(tNFA_RF_COMM_PARAMS));

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_Deactivate
**
** Description
**                  If sleep_mode=TRUE:
**                      Deselect the activated device by deactivating into sleep
**                      mode.
**
**                      An NFA_DEACTIVATE_FAIL_EVT indicates that selection was
**                      not successful. Application can select another
**                      discovered device or deactivate by NFA_Deactivate()
**                      after receiving NFA_DEACTIVATED_EVT.
**
**                      Deactivating to sleep mode is not allowed when NFCC is
**                      in wait-for-host-select mode, or in listen-sleep states;
**                      NFA will deactivate to idle or discovery state for these
**                      cases respectively.
**
**
**                  If sleep_mode=FALSE:
**                      Deactivate the connection (e.g. as a result of presence
**                      check failure) NFA_DEACTIVATED_EVT will indicate that
**                      link is deactivated. Polling/listening will resume
**                      (unless the nfcc is in wait_for-all-discoveries state)
**
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
extern tNFA_STATUS NFA_Deactivate(bool sleep_mode) {
  tNFA_DM_API_DEACTIVATE* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("sleep_mode:%i", sleep_mode);

  p_msg = (tNFA_DM_API_DEACTIVATE*)GKI_getbuf(
      (uint16_t)(sizeof(tNFA_DM_API_DEACTIVATE)));
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_DEACTIVATE_EVT;
    p_msg->sleep_mode = sleep_mode;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_SendRawFrame
**
** Description      Send a raw frame over the activated interface with the NFCC.
**                  This function can only be called after NFC link is
**                  activated.
**
**                  If the activated interface is a tag and auto-presence check
**                  is enabled then presence_check_start_delay can be used to
**                  indicate the delay in msec after which the next auto
**                  presence check command can be sent.
**                  NFA_DM_DEFAULT_PRESENCE_CHECK_START_DELAY can be used as the
**                  default value for the delay.
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_SendRawFrame(uint8_t* p_raw_data, uint16_t data_len,
                             uint16_t presence_check_start_delay) {
  NFC_HDR* p_msg;
  uint16_t size;
  uint8_t* p;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("data_len:%d", data_len);

  /* Validate parameters */
  if ((data_len == 0) || (p_raw_data == NULL))
    return (NFA_STATUS_INVALID_PARAM);

  size = NFC_HDR_SIZE + NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE + data_len;
  p_msg = (NFC_HDR*)GKI_getbuf(size);
  if (p_msg != NULL) {
    p_msg->event = NFA_DM_API_RAW_FRAME_EVT;
    p_msg->layer_specific = presence_check_start_delay;
    p_msg->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
    p_msg->len = data_len;

    p = (uint8_t*)(p_msg + 1) + p_msg->offset;
    memcpy(p, p_raw_data, data_len);

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
** NDEF Handler APIs
*******************************************************************************/

/*******************************************************************************
**
** Function         NFA_RegisterNDefTypeHandler
**
** Description      This function allows the applications to register for
**                  specific types of NDEF records. When NDEF records are
**                  received, NFA will parse the record-type field, and pass
**                  the record to the registered tNFA_NDEF_CBACK.
**
**                  For records types which were not registered, the record will
**                  be sent to the default handler. A default type-handler may
**                  be registered by calling this NFA_RegisterNDefTypeHandler
**                  with tnf=NFA_TNF_DEFAULT. In this case, all un-registered
**                  record types will be sent to the callback. Only one default
**                  handler may be registered at a time.
**
**                  An NFA_NDEF_REGISTER_EVT will be sent to the tNFA_NDEF_CBACK
**                  to indicate that registration was successful, and provide a
**                  handle for this record type.
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_RegisterNDefTypeHandler(bool handle_whole_message, tNFA_TNF tnf,
                                        uint8_t* p_type_name,
                                        uint8_t type_name_len,
                                        tNFA_NDEF_CBACK* p_ndef_cback) {
  tNFA_DM_API_REG_NDEF_HDLR* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
      "handle whole ndef message: %i, "
      "tnf=0x%02x",
      handle_whole_message, tnf);

  /* Check for NULL callback */
  if (!p_ndef_cback) {
    LOG(ERROR) << StringPrintf("error - null callback");
    return (NFA_STATUS_INVALID_PARAM);
  }

  p_msg = (tNFA_DM_API_REG_NDEF_HDLR*)GKI_getbuf(
      (uint16_t)(sizeof(tNFA_DM_API_REG_NDEF_HDLR) + type_name_len));
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_REG_NDEF_HDLR_EVT;

    p_msg->flags =
        (handle_whole_message ? NFA_NDEF_FLAGS_HANDLE_WHOLE_MESSAGE : 0);
    p_msg->tnf = tnf;
    p_msg->name_len = type_name_len;
    p_msg->p_ndef_cback = p_ndef_cback;
    memcpy(p_msg->name, p_type_name, type_name_len);

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_RegisterNDefUriHandler
**
** Description      This API is a special-case of NFA_RegisterNDefTypeHandler
**                  with TNF=NFA_TNF_WKT, and type_name='U' (URI record); and
**                  allows registering for specific URI types (e.g. 'tel:' or
**                  'mailto:').
**
**                  An NFA_NDEF_REGISTER_EVT will be sent to the tNFA_NDEF_CBACK
**                  to indicate that registration was successful, and provide a
**                  handle for this registration.
**
**                  If uri_id=NFA_NDEF_URI_ID_ABSOLUTE, then p_abs_uri contains
**                  the unabridged URI. For all other uri_id values,
**                  the p_abs_uri parameter is ignored (i.e the URI prefix is
**                  implied by uri_id). See [NFC RTD URI] for more information.
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
extern tNFA_STATUS NFA_RegisterNDefUriHandler(bool handle_whole_message,
                                              tNFA_NDEF_URI_ID uri_id,
                                              uint8_t* p_abs_uri,
                                              uint8_t uri_id_len,
                                              tNFA_NDEF_CBACK* p_ndef_cback) {
  tNFA_DM_API_REG_NDEF_HDLR* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
      "handle whole ndef message: %i, "
      "uri_id=0x%02x",
      handle_whole_message, uri_id);

  /* Check for NULL callback */
  if (!p_ndef_cback) {
    LOG(ERROR) << StringPrintf("error - null callback");
    return (NFA_STATUS_INVALID_PARAM);
  }

  p_msg = (tNFA_DM_API_REG_NDEF_HDLR*)GKI_getbuf(
      (uint16_t)(sizeof(tNFA_DM_API_REG_NDEF_HDLR) + uri_id_len));
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_REG_NDEF_HDLR_EVT;

    p_msg->flags = NFA_NDEF_FLAGS_WKT_URI;

    if (handle_whole_message) {
      p_msg->flags |= NFA_NDEF_FLAGS_HANDLE_WHOLE_MESSAGE;
    }

    /* abs_uri is only valid fir uri_id=NFA_NDEF_URI_ID_ABSOLUTE */
    if (uri_id != NFA_NDEF_URI_ID_ABSOLUTE) {
      uri_id_len = 0;
    }

    p_msg->tnf = NFA_TNF_WKT;
    p_msg->uri_id = uri_id;
    p_msg->name_len = uri_id_len;
    p_msg->p_ndef_cback = p_ndef_cback;
    memcpy(p_msg->name, p_abs_uri, uri_id_len);

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_DeregisterNDefTypeHandler
**
** Description      Deregister NDEF record type handler.
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
extern tNFA_STATUS NFA_DeregisterNDefTypeHandler(tNFA_HANDLE ndef_type_handle) {
  tNFA_DM_API_DEREG_NDEF_HDLR* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("handle 0x%08x", ndef_type_handle);

  p_msg = (tNFA_DM_API_DEREG_NDEF_HDLR*)GKI_getbuf(
      (uint16_t)(sizeof(tNFA_DM_API_DEREG_NDEF_HDLR)));
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_DEREG_NDEF_HDLR_EVT;
    p_msg->ndef_type_handle = ndef_type_handle;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_PowerOffSleepMode
**
** Description      This function is called to enter or leave NFCC Power Off
**                  Sleep mode NFA_DM_PWR_MODE_CHANGE_EVT will be sent to
**                  indicate status.
**
**                  start_stop : TRUE if entering Power Off Sleep mode
**                               FALSE if leaving Power Off Sleep mode
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_PowerOffSleepMode(bool start_stop) {
  NFC_HDR* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("start_stop=%d", start_stop);

  if (nfa_dm_cb.flags & NFA_DM_FLAGS_SETTING_PWR_MODE) {
    LOG(ERROR) << StringPrintf("NFA DM is busy to update power mode");
    return (NFA_STATUS_FAILED);
  } else {
    nfa_dm_cb.flags |= NFA_DM_FLAGS_SETTING_PWR_MODE;
  }

  p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR));
  if (p_msg != NULL) {
    p_msg->event = NFA_DM_API_POWER_OFF_SLEEP_EVT;
    p_msg->layer_specific = start_stop;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_RegVSCback
**
** Description      This function is called to register or de-register a
**                  callback function to receive Proprietary NCI response and
**                  notification events. The maximum number of callback
**                  functions allowed is NFC_NUM_VS_CBACKS
**
** Returns          tNFC_STATUS
**
*******************************************************************************/
tNFC_STATUS NFA_RegVSCback(bool is_register, tNFA_VSC_CBACK* p_cback) {
  tNFA_DM_API_REG_VSC* p_msg;

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("is_register=%d", is_register);

  if (p_cback == NULL) {
    LOG(ERROR) << StringPrintf("requires a valid callback function");
    return (NFA_STATUS_FAILED);
  }

  p_msg = (tNFA_DM_API_REG_VSC*)GKI_getbuf(sizeof(tNFA_DM_API_REG_VSC));
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_REG_VSC_EVT;
    p_msg->is_register = is_register;
    p_msg->p_cback = p_cback;

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_SendVsCommand
**
** Description      This function is called to send an NCI Vendor Specific
**                  command to NFCC.
**
**                  oid             - The opcode of the VS command.
**                  cmd_params_len  - The command parameter len
**                  p_cmd_params    - The command parameter
**                  p_cback         - The callback function to receive the
**                                    command status
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_SendVsCommand(uint8_t oid, uint8_t cmd_params_len,
                              uint8_t* p_cmd_params, tNFA_VSC_CBACK* p_cback) {
  tNFA_DM_API_SEND_VSC* p_msg;
  uint16_t size = sizeof(tNFA_DM_API_SEND_VSC) + cmd_params_len;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("oid=0x%x", oid);

  p_msg = (tNFA_DM_API_SEND_VSC*)GKI_getbuf(size);
  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_SEND_VSC_EVT;
    p_msg->oid = oid;
    p_msg->p_cback = p_cback;
    if (cmd_params_len && p_cmd_params) {
      p_msg->cmd_params_len = cmd_params_len;
      p_msg->p_cmd_params = (uint8_t*)(p_msg + 1);
      memcpy(p_msg->p_cmd_params, p_cmd_params, cmd_params_len);
    } else {
      p_msg->cmd_params_len = 0;
      p_msg->p_cmd_params = NULL;
    }

    nfa_sys_sendmsg(p_msg);

    return (NFA_STATUS_OK);
  }

  return (NFA_STATUS_FAILED);
}

/*******************************************************************************
**
** Function         NFA_SendRawVsCommand
**
** Description      This function is called to send raw Vendor Specific
**                  command to NFCC.
**
**                  cmd_params_len  - The command parameter len
**                  p_cmd_params    - The command parameter
**                  p_cback         - The callback function to receive the
**                                    command
**
** Returns          NFA_STATUS_OK if successfully initiated
**                  NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_SendRawVsCommand(uint8_t cmd_params_len, uint8_t* p_cmd_params,
                                 tNFA_VSC_CBACK* p_cback) {
  if (cmd_params_len == 0x00 || p_cmd_params == NULL || p_cback == NULL) {
    return NFA_STATUS_INVALID_PARAM;
  }
  uint16_t size = sizeof(tNFA_DM_API_SEND_VSC) + cmd_params_len;
  tNFA_DM_API_SEND_VSC* p_msg = (tNFA_DM_API_SEND_VSC*)GKI_getbuf(size);

  if (p_msg != NULL) {
    p_msg->hdr.event = NFA_DM_API_SEND_RAW_VS_EVT;
    p_msg->p_cback = p_cback;
    if (cmd_params_len && p_cmd_params) {
      p_msg->cmd_params_len = cmd_params_len;
      p_msg->p_cmd_params = (uint8_t*)(p_msg + 1);
      memcpy(p_msg->p_cmd_params, p_cmd_params, cmd_params_len);
    } else {
      p_msg->cmd_params_len = 0;
      p_msg->p_cmd_params = NULL;
    }

    nfa_sys_sendmsg(p_msg);

    return NFA_STATUS_OK;
  }

  return NFA_STATUS_FAILED;
}

/*******************************************************************************
**
** Function:        NFA_EnableDtamode
**
** Description:     Enable DTA Mode
**
** Returns:         none:
**
*******************************************************************************/
void NFA_EnableDtamode(tNFA_eDtaModes eDtaMode) {
  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("%s: 0x%x ", __func__, eDtaMode);
  appl_dta_mode_flag = 0x01;
  nfa_dm_cb.eDtaMode = eDtaMode;
}