/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
 *
 * The information contained herein is property of Nordic Semiconductor ASA.
 * Terms and conditions of usage are described in detail in NORDIC
 * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
 *
 * Licensees are granted free, non-transferable use of the information. NO
 * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
 * the file.
 */
#include "ANCS.h"
#include <string.h>
#include <stdbool.h>
#include "ble_err.h"
#include "ble_srv_common.h"
#include "nordic_common.h"
#include "nrf_assert.h"
#include "ble_bondmngr.h"
#include "ble_bondmngr_cfg.h"
#include "ble_flash.h"

#define START_HANDLE_DISCOVER           0x0001                                             /**< Value of start handle during discovery. */

#define NOTIFICATION_DATA_LENGTH        2                                                  /**< The mandatory length of notification data. After the mandatory data, the optional message is located. */
#define READ_DATA_LENGTH_MIN            1                                                  /**< Minimum data length in a valid Alert Notification Read Response message. */

#define TX_BUFFER_MASK                  0x07                                               /**< TX Buffer mask, must be a mask of contiguous zeroes, followed by contiguous sequence of ones: 000...111. */
#define TX_BUFFER_SIZE                  (TX_BUFFER_MASK + 1)                               /**< Size of send buffer, which is 1 higher than the mask. */
#define WRITE_MESSAGE_LENGTH            2                                                  /**< Length of the write message for CCCD/control point. */

#define BLE_ANCS_MAX_DISCOVERED_MASTERS  BLE_BONDMNGR_MAX_BONDED_MASTERS                    /**< Maximum number of discovered services that can be stored in the flash. This number should be identical to maximum number of bonded masters. */


#define BLE_ANCS_SERVICE_UUID_BASE     {0xD0, 0x00, 0x2D, 0x12, 0x1E, 0x4B,0x0F, 0xA4, 0x99, 0x4E, 0xCE, 0xB5,0, 0, 0x05, 0x79}
#define BLE_ANCS_SERVICE_UUID          0xF431

typedef enum
{
    READ_REQ = 1,                                                                          /**< Type identifying that this tx_message is a read request. */
    WRITE_REQ                                                                              /**< Type identifying that this tx_message is a write request. */
} ancs_tx_request_t;

typedef enum
{
    STATE_UNINITIALIZED,                                                                   /**< Uninitialized state of the internal state machine. */
    STATE_IDLE,                                                                            /**< Idle state, this is the state when no master has connected to this device. */
    STATE_DISC_SERV,                                                                       /**< A BLE master is connected and a service discovery is in progress. */
    STATE_DISC_CHAR,                                                                       /**< A BLE master is connected and characteristic discovery is in progress. */
    STATE_DISC_DESC,                                                                       /**< A BLE master is connected and descriptor discovery is in progress. */
    STATE_RUNNING,                                                                         /**< A BLE master is connected and complete service discovery has been performed. */
    STATE_WAITING_ENC,                                                                     /**< A previously bonded BLE master has re-connected and the service awaits the setup of an encrypted link. */
    STATE_RUNNING_NOT_DISCOVERED,                                                          /**< A BLE master is connected and a service discovery is in progress. */
} ancs_state_t;

/**@brief Structure used for holding the characteristic found during discovery process.
 */
typedef struct
{
    ble_uuid_t
    uuid;                                                         /**< UUID identifying this characteristic. */
    ble_gatt_char_props_t
    properties;                                                   /**< Properties for this characteristic. */
    uint16_t
    handle_decl;                                                  /**< Characteristic Declaration Handle for this characteristic. */
    uint16_t
    handle_value;                                                 /**< Value Handle for the value provided in this characteristic. */
    uint16_t
    handle_cccd;                                                  /**< CCCD Handle value for this characteristic. BLE_ANS_INVALID_HANDLE if not present in the master. */
} alert_characteristic_t;

/**@brief Structure used for holding the Apple Notification Service found during discovery process.
 */
typedef struct
{
    uint8_t
    handle;                                                       /**< Handle of Alert Notification Service which identifies to which master this discovered service belongs. */
    ble_gattc_service_t
    service;                                                      /**< The GATT service holding the discovered Alert Notification Service. */
    alert_characteristic_t
    alert_notif_ctrl_point;                                       /**< Characteristic for the Alert Notification Control Point. */
    alert_characteristic_t
    alert_notif_source;                                       /**< Characteristic for the Supported New Alert category. */
    alert_characteristic_t
    alert_notif_data;                                    /**< Characteristic for the Unread Alert category. */
} alert_service_t;

/**@brief Structure for writing a message to the master, i.e. Control Point or CCCD.
 */
typedef struct
{
    uint8_t                  gattc_value[WRITE_MESSAGE_LENGTH];                            /**< The message to write. */
    ble_gattc_write_params_t
    gattc_params;                                                 /**< GATTC parameters for this message. */
} write_params_t;

/**@brief Structure for holding data to be transmitted to the connected master.
 */
typedef struct
{
    uint16_t
    conn_handle;                                                  /**< Connection handle to be used when transmitting this message. */
    ancs_tx_request_t
    type;                                                         /**< Type of this message, i.e. read or write message. */
    union
    {
        uint16_t             read_handle;                                                  /**< Read request message. */
        write_params_t       write_req;                                                    /**< Write request message. */
    } req;
} tx_message_t;

static tx_message_t
m_tx_buffer[TX_BUFFER_SIZE];                                  /**< Transmit buffer for messages to be transmitted to the master. */
static uint32_t              m_tx_insert_index =
    0;                                        /**< Current index in the transmit buffer where next message should be inserted. */
static uint32_t              m_tx_index =
    0;                                               /**< Current index in the transmit buffer from where the next message to be transmitted resides. */
static uint8_t
m_flash_page_num;                                             /**< Flash page number where discovered services for bonded masters should be stored. */

static ancs_state_t           m_client_state =
    STATE_UNINITIALIZED;                         /**< Current state of the Alert Notification State Machine. */


#define DISCOVERED_SERVICE_DB_SIZE \
    CEIL_DIV(sizeof(alert_service_t)*BLE_ANCS_MAX_DISCOVERED_MASTERS, sizeof(uint32_t))   /**< Size of bonded masters database in word size (4 byte). */

static uint32_t
m_service_db[DISCOVERED_SERVICE_DB_SIZE];                     /**< Service database for bonded masters (Word size aligned). */
static alert_service_t *
mp_service_db;                                                /**< Pointer to start of discovered services database. */
static alert_service_t       m_service;                                                    /**< Current service data. */


/**@brief Function for passing any pending request from the buffer to the stack.
 */
static void tx_buffer_process(void)
{
		ble_uuid_t ans_uuid;
		ble_gattc_handle_range_t descriptor_handle;
		BLE_UUID_CUS_ASSIGN(ans_uuid, BLE_UUID_APPLE_NOTIFICATION_SERVICE);	
    descriptor_handle.start_handle = m_service.alert_notif_source.handle_value + 1;
    descriptor_handle.end_handle = m_service.alert_notif_source.handle_value + 1;
	
    if (m_tx_index != m_tx_insert_index)
    {
				//printf("start to gattc read/write\n\r");
        uint32_t err_code;

        if (m_tx_buffer[m_tx_index].type == READ_REQ)
        {
            err_code = sd_ble_gattc_read(m_tx_buffer[m_tx_index].conn_handle,
                                         m_tx_buffer[m_tx_index].req.read_handle,
                                         0);
// 						err_code = sd_ble_gattc_char_value_by_uuid_read(m_tx_buffer[m_tx_index].conn_handle,
// 																														&ans_uuid,
// 																														&descriptor_handle);
        }
        else
        {
            err_code = sd_ble_gattc_write(m_tx_buffer[m_tx_index].conn_handle,
                                          &m_tx_buffer[m_tx_index].req.write_req.gattc_params);
        }

        if (err_code == NRF_SUCCESS)
        {
            ++m_tx_index;
            m_tx_index &= TX_BUFFER_MASK;
        }
				else
				{
						printf("ble gattc read/write error %d\n\r",err_code);
				}
    }
}


/**@brief Function for updating the current state and sending an event on discovery failure.
 */
static void handle_discovery_failure(const ble_ancs_t * p_ans, uint32_t code)
{
    ble_ancs_evt_t event;
    m_client_state        = STATE_RUNNING_NOT_DISCOVERED;
    event.evt_type        = BLE_ANCS_C_EVT_DISCOVER_FAILED;
    event.data.error_code = code;
    p_ans->evt_handler(&event);
}


/**@brief Function for executing the Service Discovery Procedure.
 */
static void service_disc_req_send(const ble_ancs_t * p_ans)
{
    uint16_t   handle = START_HANDLE_DISCOVER;
    ble_uuid_t ans_uuid;
    uint32_t   err_code;
    // Discover services on uuid Alert Notification.
    printf("Service Discovery Procedure\n");
    BLE_UUID_CUS_ASSIGN(ans_uuid, BLE_UUID_APPLE_NOTIFICATION_SERVICE);
    err_code = sd_ble_gattc_primary_services_discover(p_ans->conn_handle, handle, &ans_uuid);

    if (err_code != NRF_SUCCESS)
    {
        handle_discovery_failure(p_ans, err_code);
    }
    else
    {
        m_client_state = STATE_DISC_SERV;
    }
}


/**@brief Function for executing the Characteristic Discovery Procedure.
 */
static void characteristic_disc_req_send(const ble_ancs_t *              p_ans,
        const ble_gattc_handle_range_t * p_handle)
{
    uint32_t err_code;
    // With valid service, we should discover characteristics.
    err_code = sd_ble_gattc_characteristics_discover(p_ans->conn_handle, p_handle);
    printf("to run sd_ble_gattc_characteristics_discover\n");

    if (err_code == NRF_SUCCESS)
    {
        m_client_state = STATE_DISC_CHAR;
    }
    else
    {
        handle_discovery_failure(p_ans, err_code);
    }
}


/**@brief Function for executing the Characteristic Descriptor Discovery Procedure.
 */
static void descriptor_disc_req_send(const ble_ancs_t * p_ans)
{
    ble_gattc_handle_range_t descriptor_handle;
    uint32_t                 err_code = NRF_SUCCESS;

    // If we have not discovered descriptors for all characteristics,
    // we will discover next descriptor.
    if (m_service.alert_notif_source.handle_cccd == BLE_ANCS_INVALID_HANDLE)
    {
        printf("the alert_notif_source cccd\n\r");
        descriptor_handle.start_handle = m_service.alert_notif_source.handle_value + 1;
        descriptor_handle.end_handle = m_service.alert_notif_source.handle_value + 1;
        err_code = sd_ble_gattc_descriptors_discover(p_ans->conn_handle, &descriptor_handle);
    }
    else if (m_service.alert_notif_data.handle_cccd == BLE_ANCS_INVALID_HANDLE)
    {
        printf("the alert_notif_data cccd\n\r");
        descriptor_handle.start_handle = m_service.alert_notif_data.handle_value + 1;
        descriptor_handle.end_handle = m_service.alert_notif_data.handle_value + 1;
        err_code = sd_ble_gattc_descriptors_discover(p_ans->conn_handle, &descriptor_handle);
    }

    if (err_code == NRF_SUCCESS)
    {
        printf("m_client_state to STATE_DISC_DESC\n\r");
        m_client_state = STATE_DISC_DESC;
    }
    else
    {
        handle_discovery_failure(p_ans, err_code);
    }
}


/**@brief Function for indicating that a connection has successfully been established.
 *        Either when the Service Discovery Procedure completes or a re-connection has been
 *        established to a bonded master.
 *
 * @details This function is executed when a service discovery or a re-connect to a bonded master
 *          occurs. In the event of re-connection to a bonded master, this function will ensure
 *          writing of the control point according to the Alert Notification Service Client
 *          specification.
 *          Finally an event is passed to the application:
 *          BLE_ANS_C_EVT_RECONNECT         - When we are connected to an existing master and the
 *                                            alert notification control point has been written.
 *          BLE_ANS_C_EVT_DISCOVER_COMPLETE - When we are connected to a new master and the Service
 *                                            Discovery has been completed.
 */
static void connection_established(const ble_ancs_t * p_ans)
{
    ble_ancs_evt_t event;
    m_client_state = STATE_RUNNING;

    if (m_service.handle == INVALID_SERVICE_HANDLE)
    {
        m_service.handle = INVALID_SERVICE_HANDLE_DISC;
    }

    if (p_ans->master_handle != INVALID_MASTER_HANDLE &&
        m_service.handle < INVALID_SERVICE_HANDLE_BASE)
    {
        printf("p_ans->master handle inval\n\r");
        event.evt_type = BLE_ANCS_C_EVT_RECONNECT;
        p_ans->evt_handler(&event);
    }
    else
    {
        printf("the BLE_ANS_C_EVT_DISCOVER_COMPLETE\r\n");
        event.evt_type = BLE_ANCS_C_EVT_DISCOVER_COMPLETE;
        p_ans->evt_handler(&event);
    }
}


/**@brief Function for waiting until an encrypted link has been established to a bonded master.
 */
static void encrypted_link_setup_wait(const ble_ancs_t * p_ans)
{
    m_client_state = STATE_WAITING_ENC;
}


/**@brief Function for handling the connect event when a master connects.
 *
 * @details This function will check if bonded master connects, and do the following
 *          Bonded master  - enter wait for encryption state.
 *          Unknown master - Initiate service discovery procedure.
 */
static void event_connect(ble_ancs_t * p_ans, const ble_evt_t * p_ble_evt)
{
    p_ans->conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;

    if (p_ans->master_handle != INVALID_MASTER_HANDLE)
    {
        m_service = mp_service_db[p_ans->master_handle];
        encrypted_link_setup_wait(p_ans);
    }
    else
    {
        m_service.handle = INVALID_SERVICE_HANDLE;
        service_disc_req_send(p_ans);
    }
}


/**@brief Function for handling the encrypted link event when a secure
 *        connection has been established with a master.
 *
 * @details This function will check if the service for the master is known.
 *          Service known   - Execute action running / switch to running state.
 *          Service unknown - Initiate Service Discovery Procedure.
 */
static void event_encrypted_link(ble_ancs_t * p_ans, const ble_evt_t * p_ble_evt)
{
    // If we are setting up a bonded connection and the UUID of the service
    // is unknown, a new discovery must be performed.
    if (m_service.service.uuid.uuid != BLE_UUID_ALERT_NOTIFICATION_SERVICE)
    {
        m_service.handle = INVALID_SERVICE_HANDLE;
        service_disc_req_send(p_ans);
    }
    else
    {
        connection_established(p_ans);
    }
}


/**@brief Function for handling the response on service discovery.
 *
 * @details This function will validate the response.
 *          Invalid response - Handle discovery failure.
 *          Valid response   - Initiate Characteristic Discovery Procedure.
 */
static void event_discover_rsp(ble_ancs_t * p_ans, const ble_evt_t * p_ble_evt)
{
    if (p_ble_evt->evt.gattc_evt.gatt_status != BLE_GATT_STATUS_SUCCESS)
    {
        // We have received an  unexpected result.
        // As we are in a connected state, but can not continue
        // our service discovery, we will go to running state.
        printf("event_discover_rsp is error %d \n\r", p_ble_evt->evt.gattc_evt.gatt_status);
        handle_discovery_failure(p_ans, p_ble_evt->evt.gattc_evt.gatt_status);
    }
    else
    {
        printf("the number prim_srvc_disc_rsp count%d\n", p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.count);
        BLE_UUID_COPY_INST(m_service.service.uuid,
                           p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.services[0].uuid);

        if (p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.count > 0)
        {
            const ble_gattc_service_t * p_service;
            p_service = &(p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.services[0]);
            m_service.service.handle_range.start_handle = p_service->handle_range.start_handle;
            m_service.service.handle_range.end_handle   = p_service->handle_range.end_handle;
            characteristic_disc_req_send(p_ans, &(m_service.service.handle_range));
        }
        else
        {
            // If we receive an answer, but it contains no service, we just go to state: Running.
            handle_discovery_failure(p_ans, p_ble_evt->evt.gattc_evt.gatt_status);
        }
    }
}


/**@brief Function for setting the discovered characteristics in the alert service.
 */
static void characteristics_set(alert_characteristic_t * p_characteristic,
                                const ble_gattc_char_t * p_char_resp)
{
    BLE_UUID_COPY_INST(p_characteristic->uuid, p_char_resp->uuid);
    p_characteristic->properties   = p_char_resp->char_props;
    p_characteristic->handle_decl  = p_char_resp->handle_decl;
    p_characteristic->handle_value = p_char_resp->handle_value;
    p_characteristic->handle_cccd  = BLE_ANCS_INVALID_HANDLE;
}


/**@brief Function for handling a characteristic discovery response event.
 *
 * @details This function will validate and store the characteristics received.
 *          If not all characteristics are discovered it will continue the characteristic discovery
 *          procedure, otherwise it will continue with the descriptor discovery procedure.
 *          If we receive a GATT Client error, we will go to handling of discovery failure.
 */
static void event_characteristic_rsp(ble_ancs_t * p_ans, const ble_evt_t * p_ble_evt)
{
    if (p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND ||
        p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_INVALID_HANDLE)
    {
        printf("the BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND and INVALID_HANDLE\n\r");

        if ((m_service.alert_notif_ctrl_point.handle_value == 0)    ||
            (m_service.alert_notif_source.handle_value == 0)    ||
            (m_service.alert_notif_data.handle_value == 0))
        {
            // At least one required characteristic is missing on the server side.
            handle_discovery_failure(p_ans, NRF_ERROR_NOT_FOUND);
        }
        else
        {
            printf("descriptor_disc_req_send\n\r");
            descriptor_disc_req_send(p_ans);
        }
    }
    else if (p_ble_evt->evt.gattc_evt.gatt_status)
    {
        // We have received an  unexpected result.
        // As we are in a connected state, but can not continue
        // our service discovery, we must go to running state.
        printf("unexpected result\r\n");
        handle_discovery_failure(p_ans, p_ble_evt->evt.gattc_evt.gatt_status);
    }
    else
    {
        uint32_t                 i;
        const ble_gattc_char_t * p_char_resp = NULL;

        // Iterate trough the characteristics and find the correct one.
        for (i = 0; i < p_ble_evt->evt.gattc_evt.params.char_disc_rsp.count; i++)
        {
            p_char_resp = &(p_ble_evt->evt.gattc_evt.params.char_disc_rsp.chars[i]);
            //printf("the uuid %d\r\n", p_char_resp->uuid.uuid);

            switch (p_char_resp->uuid.uuid)
            {
            case BLE_APP_NOTIFI_SOURCE:
                printf("BLE_APP_NOTIFI_SOURCE\r\n");
                characteristics_set(&m_service.alert_notif_source, p_char_resp);
                break;

            case BLE_APP_CONTROL_POINT:
                printf("BLE_APP_CONTROL_POINT\r\n");
                characteristics_set(&m_service.alert_notif_ctrl_point, p_char_resp);
                break;

            case BLE_APP_DATA_SOURCE:
                printf("BLE_UUID_NEW_ALERT_CHAR\r\n");
                characteristics_set(&m_service.alert_notif_data, p_char_resp);
                break;

            default:
                break;
            }
        }

        if (p_char_resp != NULL)
        {
            // If not all characteristics are received, we do a 2nd/3rd/... round.
            ble_gattc_handle_range_t char_handle;
            char_handle.start_handle = p_char_resp->handle_value + 1;
            char_handle.end_handle   = m_service.service.handle_range.end_handle;
            characteristic_disc_req_send(p_ans, &char_handle);
            printf("not all characteristics are received\r\n");
        }
        else
        {
            printf("all characteristics are received \r\n");
            characteristic_disc_req_send(p_ans, &(m_service.service.handle_range));
        }
    }
}


/**@brief Function for setting the discovered descriptor in the alert service.
 */
static void descriptor_set(alert_service_t * p_service, const ble_gattc_desc_t * p_desc_resp)
{
    if (p_service->alert_notif_source.handle_value == (p_desc_resp->handle - 1) &&
        p_desc_resp->uuid.uuid == BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG)
    {
        p_service->alert_notif_source.handle_cccd = p_desc_resp->handle;
    }
    else if (p_service->alert_notif_data.handle_value == (p_desc_resp->handle - 1) &&
             p_desc_resp->uuid.uuid == BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG)
    {
        p_service->alert_notif_data.handle_cccd = p_desc_resp->handle;
    }
}


/**@brief Function for handling of descriptor discovery responses.
 *
 * @details This function will validate and store the descriptor received.
 *          If not all descriptors are discovered it will continue the descriptor discovery
 *          procedure, otherwise it will continue to running state.
 *          If we receive a GATT Client error, we will go to handling of discovery failure.
 */
static void event_descriptor_rsp(ble_ancs_t * p_ans, const ble_evt_t * p_ble_evt)
{
    if (p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND ||
        p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_INVALID_HANDLE)
    {
        handle_discovery_failure(p_ans, NRF_ERROR_NOT_FOUND);
    }
    else if (p_ble_evt->evt.gattc_evt.gatt_status)
    {
        // We have received an unexpected result.
        // As we are in a connected state, but can not continue
        // our descriptor discovery, we will go to running state.
        handle_discovery_failure(p_ans, p_ble_evt->evt.gattc_evt.gatt_status);
    }
    else
    {
        if (p_ble_evt->evt.gattc_evt.params.desc_disc_rsp.count > 0)
        {
            printf("desc_disc_rsp.count %d \n\r", p_ble_evt->evt.gattc_evt.params.desc_disc_rsp.count);
            descriptor_set(&m_service, &(p_ble_evt->evt.gattc_evt.params.desc_disc_rsp.descs[0]));
        }

        if (m_service.alert_notif_source.handle_cccd == BLE_ANCS_INVALID_HANDLE ||
            m_service.alert_notif_data.handle_cccd == BLE_ANCS_INVALID_HANDLE)
        {
            printf("descriptor_disc_req_send\n\r");
            descriptor_disc_req_send(p_ans);
        }
        else
        {
            printf("connection_established\n\r");
            connection_established(p_ans);
        }
    }
}


/**@brief Function for receiving and validating notifications received from the master.
 */
static void event_notify(ble_ancs_t * p_ans, const ble_evt_t * p_ble_evt)
{
    uint8_t isNotiSour=true;
    ble_ancs_evt_t                event;
    ble_ancs_notification_t * p_alert = &event.data.alert;
    const ble_gattc_evt_hvx_t *    p_notification = &p_ble_evt->evt.gattc_evt.params.hvx;
    // Message is not valid -> ignore.
    event.evt_type = BLE_ANCS_C_EVT_NOTIFICATION;
    if (p_notification->len < NOTIFICATION_DATA_LENGTH)
    {
        return;
    }

    if (p_notification->handle == m_service.alert_notif_source.handle_value)
    {
				printf("get notifiaction form notif_source %d\n\r",p_notification->data[2]);
        BLE_UUID_COPY_INST(event.uuid, m_service.alert_notif_source.uuid);
    }
    else if (p_notification->handle == m_service.alert_notif_data.handle_value)
    {
        isNotiSour=false;
				printf("get notifiaction form alert_notif_data\n\r");
        BLE_UUID_COPY_INST(event.uuid, m_service.alert_notif_data.uuid);
    }
    else
    {
        // Nothing to process.
        return;
    }
    p_alert->u8EventID=p_notification->data[0];
    p_alert->u8CategoryID=p_notification->data[2];
    p_alert->u8CategoryCount=p_notification->data[3];
    p_alert->u8NotiUID[0]=p_notification->data[4];
    p_alert->u8NotiUID[1]=p_notification->data[5];
    p_alert->u8NotiUID[2]=p_notification->data[6];
    p_alert->u8NotiUID[3]=p_notification->data[7];
    p_ans->evt_handler(&event);
}


/**@brief Function for handling write response events.
 */
static void event_write_rsp(ble_ancs_t * p_ans, const ble_evt_t * p_ble_evt)
{
    tx_buffer_process();
}


/**@brief Function for validating and passing the response to the application,
 *			when a read response is received.
 */
static void event_read_rsp(ble_ancs_t * p_ans, const ble_evt_t * p_ble_evt)
{
    ble_ancs_evt_t                  event;
    const ble_gattc_evt_read_rsp_t * p_response;
    p_response     = &p_ble_evt->evt.gattc_evt.params.read_rsp;
    event.evt_type = BLE_ANCS_C_EVT_READ_RESP;
    if (p_response->len < READ_DATA_LENGTH_MIN)
    {
				printf("the response len too small\n\r");
        tx_buffer_process();
        return;
    }

    if (p_response->handle == m_service.alert_notif_source.handle_value)
    {
				printf("get the notif source\n\r");
        BLE_UUID_COPY_INST(event.uuid, m_service.alert_notif_source.uuid);
    }
    else if (p_response->handle == m_service.alert_notif_data.handle_value)
    {
				printf("get the data souce\n\r");
        BLE_UUID_COPY_INST(event.uuid, m_service.alert_notif_data.uuid);
    }
    else
    {
        // Bad response, ignore.
        tx_buffer_process();
        return;
    }

    event.data.settings = *(ble_ancs_settings_t *)(p_response->data);

    if (p_response->len == READ_DATA_LENGTH_MIN)
    {
				printf("the response len equal min data len\n\r");
        // Those must default to 0, if they are not returned by master.
        //event.data.settings.ans_high_prioritized_alert_support = 0;
        //event.data.settings.ans_instant_message_support        = 0;
    }

    p_ans->evt_handler(&event);
    tx_buffer_process();
}


/**@brief Function for disconnecting and cleaning the current service.
 */
static void event_disconnect(ble_ancs_t * p_ans)
{
    ble_ancs_evt_t event;
    ancs_state_t     prev_state = m_client_state;
    m_client_state = STATE_IDLE;

    if (m_service.handle == INVALID_SERVICE_HANDLE_DISC &&
        p_ans->master_handle != INVALID_MASTER_HANDLE)
    {
        m_service.handle = p_ans->master_handle;
    }

    if (m_service.handle < BLE_ANCS_MAX_DISCOVERED_MASTERS)
    {
        mp_service_db[m_service.handle] = m_service;
    }

    memset(&m_service, 0, sizeof(alert_service_t));
    m_service.handle      = INVALID_SERVICE_HANDLE;
    p_ans->service_handle = INVALID_SERVICE_HANDLE;
    p_ans->conn_handle    = BLE_CONN_HANDLE_INVALID;
    p_ans->master_handle  = INVALID_MASTER_HANDLE;

    // Only if our previous state was RUNNING, i.e. the client had fully initialized, then the
    // application should be notified of the DISCONNECT_COMPLETE.
    if (prev_state == STATE_RUNNING)
    {
        event.evt_type = BLE_ANCS_C_EVT_DISCONN_COMPLETE;
        p_ans->evt_handler(&event);
    }
}


/**@brief Function for handling of Bond Manager events.
 */
void ble_ancs_on_bondmgmr_evt(ble_ancs_t * p_ans, const ble_bondmngr_evt_t * p_bond_mgmr_evt)
{
    switch (p_bond_mgmr_evt->evt_type)
    {
    case BLE_BONDMNGR_EVT_NEW_BOND:
        p_ans->master_handle = p_bond_mgmr_evt->master_handle;
        break;

    case BLE_BONDMNGR_EVT_CONN_TO_BONDED_MASTER:
        p_ans->master_handle = p_bond_mgmr_evt->master_handle;
        break;

    default:
        // Do nothing.
        break;
    }
}


/**@brief Function for handling of BLE stack events.
 */
void ble_ancs_on_ble_evt(ble_ancs_t * p_ans, const ble_evt_t * p_ble_evt)
{
    uint16_t event = p_ble_evt->header.evt_id;

    switch (m_client_state)
    {
    case STATE_UNINITIALIZED:
        printf("STATE_UNINITIALIZED\n");
        // Initialization is handle in special case, thus if we enter here, it means that an
        // event is received even though we are not initialized --> ignore.
        break;

    case STATE_IDLE:
        if (event == BLE_GAP_EVT_CONNECTED)
        {
            printf("BLE_GAP_EVT_CONNECTED\n");
            event_connect(p_ans, p_ble_evt);
        }

        break;

    case STATE_WAITING_ENC:
        if ((event == BLE_GAP_EVT_AUTH_STATUS) || (event == BLE_GAP_EVT_SEC_INFO_REQUEST))
        {
            printf("BLE_GAP_EVT_AUTH_STATUS||BLE_GAP_EVT_SEC_INFO_REQUEST\n");
            event_encrypted_link(p_ans, p_ble_evt);
        }
        else if (event == BLE_GAP_EVT_DISCONNECTED)
        {
            printf("BLE_GAP_EVT_DISCONNECTED\n");
            event_disconnect(p_ans);
        }

        break;

    case STATE_DISC_SERV:
        if (event == BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP)
        {
            printf("STATE_DISC_SERV\n");
            event_discover_rsp(p_ans, p_ble_evt);
        }
        else if (event == BLE_GAP_EVT_DISCONNECTED)
        {
            printf("BLE_GAP_EVT_DISCONNECTED\n");
            event_disconnect(p_ans);
        }

        break;

    case STATE_DISC_CHAR:
        if (event == BLE_GATTC_EVT_CHAR_DISC_RSP)
        {
            printf("BLE_GATTC_EVT_CHAR_DISC_RSP\n");
            event_characteristic_rsp(p_ans, p_ble_evt);
        }
        else if (event == BLE_GAP_EVT_DISCONNECTED)
        {
            printf("BLE_GAP_EVT_DISCONNECTED\n");
            event_disconnect(p_ans);
        }

        break;

    case STATE_DISC_DESC:
        if (event == BLE_GATTC_EVT_DESC_DISC_RSP)
        {
            printf("BLE_GATTC_EVT_DESC_DISC_RSP\n");
            event_descriptor_rsp(p_ans, p_ble_evt);
        }
        else if (event == BLE_GAP_EVT_DISCONNECTED)
        {
            printf("BLE_GAP_EVT_DISCONNECTED\n");
            event_disconnect(p_ans);
        }

        break;

    case STATE_RUNNING:
        if (event == BLE_GATTC_EVT_HVX)
        {
            printf("BLE_GATTC_EVT_HVX\n");
            event_notify(p_ans, p_ble_evt);
        }
        else if (event == BLE_GATTC_EVT_READ_RSP)
        {
            printf("BLE_GATTC_EVT_READ_RSP\n");
            event_read_rsp(p_ans, p_ble_evt);
        }
        else if (event == BLE_GATTC_EVT_WRITE_RSP)
        {
            printf("BLE_GATTC_EVT_WRITE_RSP\n\r");
            event_write_rsp(p_ans, p_ble_evt);
        }
        else if (event == BLE_GAP_EVT_DISCONNECTED)
        {
            printf("BLE_GAP_EVT_DISCONNECTED\n");
            event_disconnect(p_ans);
        }
				else if(event == BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP)
				{
						printf("BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP\n");						
						event_read_rsp(p_ans, p_ble_evt);						
				}
        else
        {
            // Do nothing, event not handled in this state.
        }

        break;

    case STATE_RUNNING_NOT_DISCOVERED:
        if (event == BLE_GAP_EVT_DISCONNECTED)
        {
            printf("STATE_RUNNING_NOT_DISCOVERED\n");
            event_disconnect(p_ans);
        }

        break;

    default:
        event_disconnect(p_ans);
        break;
    }
}


uint32_t ble_ancs_init(ble_ancs_t * p_ans, const ble_ancs_init_t * p_ans_init)
{
    uint32_t err_code;
    ble_uuid_t ble_uuid;
    ble_uuid128_t ans_base_uuid = {0xD0, 0x00, 0x2D, 0x12, 0x1E, 0x4B, \
                                   0x0F, 0xA4, 0x99, 0x4E, 0xCE, 0xB5, \
                                   0, 0, 0x05, 0x79
                                  };
    //7905F431-B5CE-4E99-A40F-4B1E122D00D0
    ble_uuid128_t cp_base_uuid = {0xD9, 0xD9, 0xAA, 0xFD, 0xBD, 0x9B, \
                                  0x21, 0x98, 0xA8, 0x49, 0xE1, 0x45, \
                                  0, 0, 0xD1, 0x69
                                 };
    //69,D1,D8,F3-45,E1-49,A8-98,21-9B,BD,FD,AA,D9,D9
    ble_uuid128_t ns_base_uuid = {0xBD, 0x1D, 0xA2, 0x99, 0xE6, 0x25, \
                                  0x58, 0x8C, 0xD9, 0x42, 0x01, 0x63, \
                                  0, 0, 0xBF, 0x9F
                                 };
    //9F,BF,12,0D-63,01-42,D9-8C,58-25,E6,99,A2,1D,BD,Notification Source
    ble_uuid128_t ds_base_uuid = {0xFB, 0x7B, 0x7C, 0xCE, 0x6A, 0xB3, \
                                  0x44, 0xBE, 0xB5, 0x4B, 0xD6, 0x24, \
                                  0, 0, 0xEA, 0x22
                                 };
    //22,EA,C6,E9-24,D6-4B,B5-BE,44-B3,6A,CE,7C,7B,FB ,Data Source

    if (p_ans_init->evt_handler == NULL || p_ans_init->flash_page_num == 0)
    {
        return NRF_ERROR_INVALID_PARAM;
    }

    // Add custom base UUID
    err_code = sd_ble_uuid_vs_add(&ans_base_uuid, &p_ans->uuid_type);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    // Add notification source base UUID
    err_code = sd_ble_uuid_vs_add(&ns_base_uuid, &p_ans->uuid_type);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    // Add control point base UUID
    err_code = sd_ble_uuid_vs_add(&cp_base_uuid, &p_ans->uuid_type);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    // Add data source base UUID
    err_code = sd_ble_uuid_vs_add(&ds_base_uuid, &p_ans->uuid_type);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    p_ans->evt_handler         = p_ans_init->evt_handler;
    p_ans->error_handler       = p_ans_init->error_handler;
    p_ans->service_handle      = INVALID_SERVICE_HANDLE;
    p_ans->master_handle       = INVALID_MASTER_HANDLE;
    p_ans->service_handle      = 0;
    p_ans->message_buffer_size = p_ans_init->message_buffer_size;
    p_ans->p_message_buffer    = p_ans_init->p_message_buffer;
    p_ans->conn_handle         = BLE_CONN_HANDLE_INVALID;
    memset(&m_service, 0, sizeof(alert_service_t));
    memset(m_tx_buffer, 0, TX_BUFFER_SIZE);
    m_service.handle = INVALID_SERVICE_HANDLE;
    m_client_state   = STATE_IDLE;
    m_flash_page_num = p_ans_init->flash_page_num;
    mp_service_db    = (alert_service_t *) (m_service_db);
    return NRF_SUCCESS;
}


/**@brief Function for creating a TX message for writing a CCCD.
 */
static uint32_t cccd_configure(uint16_t conn_handle, uint16_t handle_cccd, bool enable)
{
    tx_message_t * p_msg;
    uint16_t       cccd_val = enable ? BLE_CCCD_NOTIFY_BIT_MASK : 0;

    if (m_client_state != STATE_RUNNING)
    {
        return NRF_ERROR_INVALID_STATE;
    }

    p_msg              = &m_tx_buffer[m_tx_insert_index++];
    m_tx_insert_index &= TX_BUFFER_MASK;
    p_msg->req.write_req.gattc_params.handle   = handle_cccd;
    p_msg->req.write_req.gattc_params.len      = WRITE_MESSAGE_LENGTH;
    p_msg->req.write_req.gattc_params.p_value  = p_msg->req.write_req.gattc_value;
    p_msg->req.write_req.gattc_params.offset   = 0;
    p_msg->req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
    p_msg->req.write_req.gattc_value[0]        = LSB(cccd_val);
    p_msg->req.write_req.gattc_value[1]        = MSB(cccd_val);
    p_msg->conn_handle                         = conn_handle;
    p_msg->type                                = WRITE_REQ;
    tx_buffer_process();
    return NRF_SUCCESS;
}


uint32_t ble_ancs_enable_notif_new_alert(const ble_ancs_t * p_ans)
{
    return cccd_configure(p_ans->conn_handle,
                          m_service.alert_notif_source.handle_cccd,
                          true);
}

uint32_t ble_ancs_enable_notif_data(const ble_ancs_t * p_ans)
{
    return cccd_configure(p_ans->conn_handle,
                          m_service.alert_notif_data.handle_cccd,
                          true);
}


uint32_t ble_ancs_disable_notif_new_alert(const ble_ancs_t * p_ans)
{
    return cccd_configure(p_ans->conn_handle,
                          m_service.alert_notif_source.handle_cccd,
                          false);    
}

uint32_t ble_ancs_disable_notif_data(const ble_ancs_t * p_ans)
{
    return cccd_configure(p_ans->conn_handle,
                          m_service.alert_notif_data.handle_cccd,
                          false);    
}

uint32_t ble_ancs_control_point_write(const ble_ancs_t *             p_ans,
                                      const ble_ancs_control_point_t * p_control_point)
{
    tx_message_t * p_msg;

    if (m_client_state != STATE_RUNNING)
    {
        return NRF_ERROR_INVALID_STATE;
    }

    p_msg              = &m_tx_buffer[m_tx_insert_index++];
    m_tx_insert_index &= TX_BUFFER_MASK;
    p_msg->req.write_req.gattc_params.handle   = m_service.alert_notif_ctrl_point.handle_value;
    p_msg->req.write_req.gattc_params.len      = WRITE_MESSAGE_LENGTH;
    p_msg->req.write_req.gattc_params.p_value  = p_msg->req.write_req.gattc_value;
    p_msg->req.write_req.gattc_params.offset   = 0;
    p_msg->req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
    p_msg->req.write_req.gattc_value[0]        = p_control_point->command;
    //p_msg->req.write_req.gattc_value[1]        = p_control_point->category;
    p_msg->conn_handle                         = p_ans->conn_handle;
    p_msg->type                                = WRITE_REQ;
    tx_buffer_process();
    return NRF_SUCCESS;
}

/*subscribe to notification source*/
uint32_t ble_ancs_new_alert_read(const ble_ancs_t * p_ans)
{
    tx_message_t * msg;
    msg                  = &m_tx_buffer[m_tx_insert_index++];
    m_tx_insert_index   &= TX_BUFFER_MASK;
    msg->req.read_handle = m_service.alert_notif_source.handle_value;
    msg->conn_handle     = p_ans->conn_handle;
    msg->type            = READ_REQ;
    tx_buffer_process();
    return NRF_SUCCESS;
}

/*subscribe to data source*/
uint32_t ble_ancs_noti_data_read(const ble_ancs_t * p_ans)
{
    tx_message_t * msg;
    msg                  = &m_tx_buffer[m_tx_insert_index++];
    m_tx_insert_index   &= TX_BUFFER_MASK;
    msg->req.read_handle = m_service.alert_notif_data.handle_value;
    msg->conn_handle     = p_ans->conn_handle;
    msg->type            = READ_REQ;
    tx_buffer_process();
    return NRF_SUCCESS;
}

uint32_t ble_ancs_new_alert_notify(const ble_ancs_t * p_ans, ble_ancs_category_id_t category_id)
{
    ble_ancs_control_point_t control_point;
    //control_point.command  = ANS_NOTIFY_NEW_INCOMING_ALERT_IMMEDIATELY;
    //control_point.category = category_id;
    return ble_ancs_control_point_write(p_ans, &control_point);
}

uint32_t ble_ancs_service_load(const ble_ancs_t * p_ans)
{
    uint32_t err_code;
    uint8_t  word_count;
    uint32_t i;
    err_code = ble_flash_page_read(m_flash_page_num, m_service_db, &word_count);

    if (err_code != NRF_SUCCESS)
    {
        // Problem with loading values from flash, initialize the RAM DB with default.
        for (i = 0; i < BLE_ANCS_MAX_DISCOVERED_MASTERS; ++i)
        {
            mp_service_db[i].handle = INVALID_SERVICE_HANDLE;
        }

        if (err_code == NRF_ERROR_NOT_FOUND)
        {
            // The flash does not contain any memorized masters, set the return code to success.
            err_code = NRF_SUCCESS;
        }
    }

    return err_code;
}


uint32_t ble_ancs_service_store(void)
{
    uint32_t err_code;
    uint8_t  word_count;
    word_count = DISCOVERED_SERVICE_DB_SIZE;
    err_code = ble_flash_page_write(m_flash_page_num, m_service_db, word_count);
    return err_code;
}

uint32_t ble_ancs_service_delete(void)
{
    if (m_client_state == STATE_UNINITIALIZED)
    {
        return NRF_SUCCESS;
    }

    return ble_flash_page_erase(m_flash_page_num);
}
