This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

ble_ancs_C

I have a question about that code, when I test my code with lightblue, it showed me that there is an service called application notification client service, but it didn't show me any of its charactersitics, however it showed me that there are other services & showed also their charactersitics, when I tested the code with an android OS I found that it didn't show ANCS service, I/m confused about that & don't know how to show the ANCS characterisitics.

	/* 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.
 */
 
/* Disclaimer: This client implementation of the Apple Notification Center Service can and will be changed at any time by Nordic Semiconductor ASA.
 * Server implementations such as the ones found in iOS can be changed at any time by Apple and may cause this client implementation to stop working.
 */

#include "ble_ancs_c.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 "device_manager.h"
#include "ble_db_discovery.h"
#include "app_error.h"
#include "app_trace.h"

#define BLE_ANCS_NOTIF_EVT_ID_INDEX       0                       /**< Index of the Event ID field when parsing notifications. */
#define BLE_ANCS_NOTIF_FLAGS_INDEX        1                       /**< Index of the Flags field when parsing notifications. */
#define BLE_ANCS_NOTIF_CATEGORY_ID_INDEX  2                       /**< Index of the Category ID field when parsing notifications. */
#define BLE_ANCS_NOTIF_CATEGORY_CNT_INDEX 3                       /**< Index of the Category Count field when parsing notifications. */
#define BLE_ANCS_NOTIF_NOTIF_UID          4                       /**< Index of the Notification UID field when patsin notifications. */

#define LOG                              app_trace_log            /**< Debug logger macro that will be used in this file to do logging of important information over UART. */
#define LOG_DUMP                         app_trace_dump           /**< Debug logger macro that will be used in this file to do logging of important information over UART. */

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

#define TX_BUFFER_MASK                   0x07                     /**< TX buffer mask. Must be a mask of contiguous zeroes followed by a 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             20                       /**< Length of the write message for CCCD/control point. */
#define BLE_CCCD_NOTIFY_BIT_MASK         0x0001                   /**< Enable notification bit. */

#define BLE_ANCS_MAX_DISCOVERED_CENTRALS DEVICE_MANAGER_MAX_BONDS /**< Maximum number of discovered services that can be stored in the flash. This number should be identical to maximum number of bonded peer devices. */

#define TIME_STRING_LEN                  15                       /**< Unicode Technical Standard (UTS) #35 date format pattern "yyyyMMdd'T'HHmmSS" + "'\0'". */

#define DISCOVERED_SERVICE_DB_SIZE \
		CEIL_DIV(sizeof(ble_ancs_c_service_t) * BLE_ANCS_MAX_DISCOVERED_CENTRALS, sizeof(uint32_t)) /**< Size of bonded peer's database in word size (4 byte). */


/**@brief ANCS request types.
 */
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;


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


/**@brief Structure used for holding the Apple Notification Center Service found during the discovery process.
 */
typedef struct
{
		uint8_t                     handle;         /**< Handle of Apple Notification Center Service, which identifies to which peer this discovered service belongs. */
		ble_gattc_service_t         service;        /**< The GATT Service holding the discovered Apple Notification Center Service. */
		ble_ancs_c_characteristic_t control_point;  /**< Control Point Characteristic for the service. Allows interaction with the peer. */
		ble_ancs_c_characteristic_t notif_source;   /**< Characteristic that keeps track of arrival, modification, and removal of notifications. */
		ble_ancs_c_characteristic_t data_source;    /**< Characteristic where attribute data for the notifications is received from peer. */
} ble_ancs_c_service_t;


/**@brief Structure for writing a message to the central, 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;


/**@brief Parsing states for received iOS notification attributes.
 */
typedef enum
{
		COMMAND_ID_AND_NOTIF_UID,  /**< Parsing the command ID and the notification UID. */
		ATTR_ID,                   /**< Parsing attribute ID. */
		ATTR_LEN1,                 /**< Parsing the LSB of the attribute length. */
		ATTR_LEN2,                 /**< Parsing the MSB of the attribute length. */
		ATTR_DATA,                 /**< Parsing the attribute data. */
		DONE                       /**< Parsing is done. */
} ble_ancs_c_parse_state_t;

static tx_message_t m_tx_buffer[TX_BUFFER_SIZE];                           /**< Transmit buffer for messages to be transmitted to the Notification Provider. */
static uint32_t     m_tx_insert_index = 0;                                 /**< Current index in the transmit buffer where the 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 ble_ancs_c_service_t   m_service;                                   /**< Current service data. */
static ble_ancs_c_t         * mp_ble_ancs;                                 /**< Pointer to the current instance of the ANCS client module. The memory for this is provided by the application.*/
static ble_ancs_c_attr_list_t m_ancs_attr_list[BLE_ANCS_NB_OF_ATTRS];      /**< For all attributes; contains whether they should be requested upon attribute request and the length and buffer of where to store attribute data. */
static uint32_t               m_expected_number_of_attrs;                  /**< Variable to keep track of when to stop reading incoming attributes. */
static ble_ancs_c_evt_t       m_ancs_evt;                                  /**< The ANCS event that is created in this module and propagated to the application. */

static ble_ancs_c_parse_state_t m_parse_state = COMMAND_ID_AND_NOTIF_UID;  /**< ANCS notification attribute parsing state. */


/**@brief 128-bit service UUID for the Apple Notification Center Service.
 */
const ble_uuid128_t ble_ancs_base_uuid128 =
{
		{
				// 7905F431-B5CE-4E99-A40F-4B1E122D00D0
				0xd0, 0x00, 0x2d, 0x12, 0x1e, 0x4b, 0x0f, 0xa4,
				0x99, 0x4e, 0xce, 0xb5, 0x31, 0xf4, 0x05, 0x79
		}
};


/**@brief 128-bit control point UUID.
 */
const ble_uuid128_t ble_ancs_cp_base_uuid128 =
{
		{
				// 69d1d8f3-45e1-49a8-9821-9BBDFDAAD9D9
				0xd9, 0xd9, 0xaa, 0xfd, 0xbd, 0x9b, 0x21, 0x98,
				0xa8, 0x49, 0xe1, 0x45, 0xf3, 0xd8, 0xd1, 0x69
		}
};

/**@brief 128-bit notification source UUID.
*/
const ble_uuid128_t ble_ancs_ns_base_uuid128 =
{
		{
				// 9FBF120D-6301-42D9-8C58-25E699A21DBD
				0xbd, 0x1d, 0xa2, 0x99, 0xe6, 0x25, 0x58, 0x8c,
				0xd9, 0x42, 0x01, 0x63, 0x0d, 0x12, 0xbf, 0x9f

		}
};

/**@brief 128-bit data source UUID.
*/
const ble_uuid128_t ble_ancs_ds_base_uuid128 =
{
		{
				// 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB
				0xfb, 0x7b, 0x7c, 0xce, 0x6a, 0xb3, 0x44, 0xbe,
				0xb5, 0x4b, 0xd6, 0x24, 0xe9, 0xc6, 0xea, 0x22
		}
};


/**@brief Function for handling events from the database discovery module.
 *
 * @details This function handles events from the database discovery module and determines
 *          if it relates to the discovery of the Apple Notification Center Service at the 
 *          peer. If so, it will call the application's event handler indicating that the Apple
 *          Notification Center Service has been discovered at the peer. It also populates the
 *          event with the service-related information before providing it to the application.
 *
 * @param[in] p_evt Pointer to the event received from the database discovery module.
 */
static void db_discover_evt_handler(ble_db_discovery_evt_t * p_evt)
{
		LOG("[ANCS]: Database Discovery handler called with event 0x%x\r\n", p_evt->evt_type);

		ble_ancs_c_evt_t evt;
		ble_db_discovery_char_t * p_chars;

		p_chars = p_evt->params.discovered_db.charateristics;

		// Check if the ANCS Service was discovered.
		if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
				p_evt->params.discovered_db.srv_uuid.uuid == ANCS_UUID_SERVICE &&
				p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_VENDOR_BEGIN)
		{
				mp_ble_ancs->conn_handle = p_evt->conn_handle;

				// Find the handles of the ANCS characteristic.
				uint32_t i;

				for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
				{
						switch (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid)
						{
								case ANCS_UUID_CHAR_CONTROL_POINT:
										LOG("[ANCS]: Control Point Characteristic found.\n\r");
										m_service.control_point.properties   = p_chars[i].characteristic.char_props;
										m_service.control_point.handle_decl  = p_chars[i].characteristic.handle_decl;
										m_service.control_point.handle_value = p_chars[i].characteristic.handle_value;
										m_service.control_point.handle_cccd  = p_chars[i].cccd_handle;
										break;

								case ANCS_UUID_CHAR_DATA_SOURCE:
										LOG("[ANCS]: Data Source Characteristic found.\n\r");
										m_service.data_source.properties   = p_chars[i].characteristic.char_props;
										m_service.data_source.handle_decl  = p_chars[i].characteristic.handle_decl;
										m_service.data_source.handle_value = p_chars[i].characteristic.handle_value;
										m_service.data_source.handle_cccd  = p_chars[i].cccd_handle;
										break;

								case ANCS_UUID_CHAR_NOTIFICATION_SOURCE:
										LOG("[ANCS]: Notification point Characteristic found.\n\r");
										m_service.notif_source.properties   = p_chars[i].characteristic.char_props;
										m_service.notif_source.handle_decl  = p_chars[i].characteristic.handle_decl;
										m_service.notif_source.handle_value = p_chars[i].characteristic.handle_value;
										m_service.notif_source.handle_cccd  = p_chars[i].cccd_handle;
										break;

								default:
										break;
						}
				}
				evt.evt_type = BLE_ANCS_C_EVT_DISCOVER_COMPLETE;
				mp_ble_ancs->evt_handler(&evt);
		}
		else
		{
				evt.evt_type = BLE_ANCS_C_EVT_DISCOVER_FAILED;
				mp_ble_ancs->evt_handler(&evt);
		}
}


/**@brief Function for passing any pending request from the buffer to the stack.
 */
static void tx_buffer_process(void)
{
		if (m_tx_index != m_tx_insert_index)
		{
				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);
				}
				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;
				}
		}
}


/**@brief Function for parsing received notification attribute response data.
 *
 * @details The data that comes from the Notification Provider can be much longer than what
 *          would fit in a single GATTC notification. Therefore, function relies on static
 *          variables and a state-oriented switch case.
 *          UID and command ID will be received only once at the beginning of the first 
 *          GATTC notification of a new attribute request for a given iOS notification.
 *          After this, we can loop several ID > LENGTH > DATA > ID > LENGTH > DATA until we have
 *          received all attributes we wanted as a Notification Consumer. The Notification Provider
 *          can also simply stop sending attributes.
 *
 * @param[in] p_ancs     Pointer to an ANCS instance to which the event belongs.
 * @param[in] p_data_src Pointer to data that was received from the Notification Provider.
 * @param[in] hvx_len    Length of the data that was received from the Notification Provider.
 */
static void parse_get_notif_attrs_response(ble_ancs_c_t  * p_ancs,
																					 const uint8_t * p_data_src,
																					 const uint16_t  hvx_data_len)
{
		static uint8_t               * p_data_dest;
		static uint16_t                current_attr_index;
		static ble_ancs_c_evt_t        evt;
		ble_ancs_c_command_id_values_t command_id;
		uint32_t                       index;

		evt.ancs_attr_list = m_ancs_attr_list;

		for (index = 0; index < hvx_data_len;)
		{
				switch (m_parse_state)
				{
						case COMMAND_ID_AND_NOTIF_UID:
								command_id = (ble_ancs_c_command_id_values_t) p_data_src[index++];
								if(command_id != BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES)
								{
										LOG("[ANCS]: Invalid Command ID");
										m_parse_state = DONE;
								}

								evt.attr.notif_uid  = uint32_decode(&p_data_src[index]);
								index              += sizeof(uint32_t);
								m_parse_state       = ATTR_ID;

								if (evt.attr.notif_uid != m_ancs_evt.notif.notif_uid)
								{
										LOG("UID mismatch: Notification UID %x , Attribute UID %x\n\r",
												evt.notif.notif_uid,
												evt.attr.notif_uid);
										m_parse_state = DONE;
								}
								break;

						case ATTR_ID:
								if (m_expected_number_of_attrs == 0)
								{
										LOG("[ANCS]: All requested attributes received\n\r");
										m_parse_state = DONE;
										index++;
								}
								else
								{
										evt.attr.attr_id = (ble_ancs_c_notif_attr_id_values_t) p_data_src[index++];
										p_data_dest        = m_ancs_attr_list[evt.attr.attr_id].p_attr_data;
										if (m_ancs_attr_list[evt.attr.attr_id].get == true)
										{
												m_parse_state = ATTR_LEN1;
										}
										m_expected_number_of_attrs--;
										LOG("Attribute ID %i \n\r", evt.attr.attr_id);
								}
								break;

						case ATTR_LEN1:
								evt.attr.attr_len = p_data_src[index++];
								m_parse_state       = ATTR_LEN2;
								break;

						case ATTR_LEN2:
								evt.attr.attr_len |= (p_data_src[index++] << 8);
								current_attr_index   = 0;
								if (evt.attr.attr_len != 0)
								{
										m_parse_state = ATTR_DATA;
								}
								else
								{
										evt.evt_type = BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE;
										p_ancs->evt_handler(&evt);
										m_parse_state = ATTR_ID;
								}
								LOG("Attribute LEN %i \n\r", evt.attr.attr_len);
								break;

						case ATTR_DATA:
								// We have not reached the end of the attribute, nor our max allocated internal size.
								// Proceed with copying data over to our buffer.
								if (   (current_attr_index < m_ancs_attr_list[evt.attr.attr_id].attr_len)
										&& (current_attr_index < evt.attr.attr_len))
								{
										p_data_dest[current_attr_index++] = p_data_src[index++];
								}
								// We have reached the end of the attribute, or our max allocated internal size.
								// Stop copying data over to our buffer. NUL-terminate at the current index.
								if ( (current_attr_index == evt.attr.attr_len) ||
										 (current_attr_index == m_ancs_attr_list[evt.attr.attr_id].attr_len))
								{
										p_data_dest[current_attr_index] = '\0';
										
										// If our max buffer size is smaller than the remaining attribute data, we must
										// increase index to skip the data until the start of the next attribute.
										if (current_attr_index < evt.attr.attr_len)
										{
												index += (evt.attr.attr_len - current_attr_index);
										}
										m_parse_state = ATTR_ID;
										LOG("Attribute finished!\n\r");
										evt.evt_type = BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE;
										p_ancs->evt_handler(&evt);
								}
								break;

						case DONE:
								index = hvx_data_len;
								break;

						default:
								// Default case will never trigger intentionally. Go to the DONE state to minimize the consequences.
								m_parse_state = DONE;
								break;
				}
		}
}


/**@brief Function for checking if data in an iOS notification is out of bounds.
 *
 * @param[in] notif  An iOS notification.
 *
 * @retval NRF_SUCCESS             If the notification is within bounds.
 * @retval NRF_ERROR_INVALID_PARAM If the notification is out of bounds.
 */
static uint32_t ble_ancs_verify_notification_format(const ble_ancs_c_evt_notif_t * notif)
{
		if(   (notif->evt_id >= BLE_ANCS_NB_OF_EVT_ID)
			 || (notif->category_id >= BLE_ANCS_NB_OF_CATEGORY_ID))
		{
				return NRF_ERROR_INVALID_PARAM;
		}
		return NRF_SUCCESS;
}

/**@brief Function for receiving and validating notifications received from the Notification Provider.
 * 
 * @param[in] p_ancs     Pointer to an ANCS instance to which the event belongs.
 * @param[in] p_ble_evt  Bluetooth stack event.
 * @param[in] p_data_src Pointer to data that was received from the Notification Provider.
 * @param[in] hvx_len    Length of the data that was received by the Notification Provider.
 */
static void parse_notif(const ble_ancs_c_t * p_ancs,
												ble_ancs_c_evt_t   * p_ancs_evt,
												const uint8_t      * p_data_src,
												const uint16_t       hvx_data_len)
{
		uint32_t err_code;
		if (hvx_data_len != BLE_ANCS_NOTIFICATION_DATA_LENGTH)
		{
				m_ancs_evt.evt_type = BLE_ANCS_C_EVT_INVALID_NOTIF;
				p_ancs->evt_handler(&m_ancs_evt);
		}

		/*lint --e{415} --e{416} -save suppress Warning 415: possible access out of bond */
		p_ancs_evt->notif.evt_id                    =
						(ble_ancs_c_evt_id_values_t) p_data_src[BLE_ANCS_NOTIF_EVT_ID_INDEX];

		p_ancs_evt->notif.evt_flags.silent          =
						(p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_SILENT) & 0x01;

		p_ancs_evt->notif.evt_flags.important       =
						(p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_IMPORTANT) & 0x01;

		p_ancs_evt->notif.evt_flags.pre_existing    =
						(p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_PREEXISTING) & 0x01;

		p_ancs_evt->notif.evt_flags.positive_action =
						(p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_POSITIVE_ACTION) & 0x01;

		p_ancs_evt->notif.evt_flags.negative_action =
						(p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_NEGATIVE_ACTION) & 0x01;

		p_ancs_evt->notif.category_id               =
				(ble_ancs_c_category_id_values_t) p_data_src[BLE_ANCS_NOTIF_CATEGORY_ID_INDEX];

		p_ancs_evt->notif.category_count            = p_data_src[BLE_ANCS_NOTIF_CATEGORY_CNT_INDEX];
		p_ancs_evt->notif.notif_uid = uint32_decode(&p_data_src[BLE_ANCS_NOTIF_NOTIF_UID]);
		/*lint -restore*/

		err_code = ble_ancs_verify_notification_format(&m_ancs_evt.notif);
		if (err_code == NRF_SUCCESS)
		{
				m_ancs_evt.evt_type = BLE_ANCS_C_EVT_NOTIF;
		}
		else
		{
				m_ancs_evt.evt_type = BLE_ANCS_C_EVT_INVALID_NOTIF;
		}

		p_ancs->evt_handler(&m_ancs_evt);
}


/**@brief Function for receiving and validating notifications received from the Notification Provider.
 * 
 * @param[in] p_ancs    Pointer to an ANCS instance to which the event belongs.
 * @param[in] p_ble_evt Bluetooth stack event.
 */
static void on_evt_gattc_notif(ble_ancs_c_t * p_ancs, const ble_evt_t * p_ble_evt)
{
		const ble_gattc_evt_hvx_t * p_notif = &p_ble_evt->evt.gattc_evt.params.hvx;

		if (p_notif->handle == m_service.notif_source.handle_value)
		{
				BLE_UUID_COPY_INST(m_ancs_evt.uuid, m_service.notif_source.uuid);
				parse_notif(p_ancs, &m_ancs_evt,p_notif->data,p_notif->len);
		}
		else if (p_notif->handle == m_service.data_source.handle_value)
		{
				BLE_UUID_COPY_INST(m_ancs_evt.uuid, m_service.data_source.uuid);
				parse_get_notif_attrs_response(p_ancs, p_notif->data, p_notif->len);
		}
		else
		{
				// No applicable action.
		}
}

/**@brief Function for handling write response events.
 */
static void on_evt_write_rsp()
{
		tx_buffer_process();
}


void ble_ancs_c_on_device_manager_evt(ble_ancs_c_t      * p_ans,
																			dm_handle_t const * p_handle,
																			dm_event_t const  * p_dm_evt)
{
		switch (p_dm_evt->event_id)
		{
				case DM_EVT_CONNECTION:
						// Fall through.
				case DM_EVT_SECURITY_SETUP_COMPLETE:
						p_ans->central_handle = p_handle->device_id;
						break;

				default:
						// Do nothing.
						break;
		}
}


void ble_ancs_c_on_ble_evt(ble_ancs_c_t * p_ancs, const ble_evt_t * p_ble_evt)
{
		uint16_t evt = p_ble_evt->header.evt_id;

		switch (evt)
		{
				case BLE_GATTC_EVT_WRITE_RSP:
						on_evt_write_rsp();
						break;

				case BLE_GATTC_EVT_HVX:
						on_evt_gattc_notif(p_ancs, p_ble_evt);
						break;

				default:
						break;
		}
}


uint32_t ble_ancs_c_init(ble_ancs_c_t * p_ancs, const ble_ancs_c_init_t * p_ancs_init)
{
		if ((p_ancs == NULL) || p_ancs_init == NULL || (p_ancs_init->evt_handler == NULL))
		{
				return NRF_ERROR_NULL;
		}

		mp_ble_ancs = p_ancs;

		mp_ble_ancs->evt_handler    = p_ancs_init->evt_handler;
		mp_ble_ancs->error_handler  = p_ancs_init->error_handler;
		mp_ble_ancs->service_handle = BLE_GATT_HANDLE_INVALID;
		mp_ble_ancs->central_handle = DM_INVALID_ID;
		mp_ble_ancs->conn_handle    = BLE_CONN_HANDLE_INVALID;

		memset(&m_service, 0, sizeof(ble_ancs_c_service_t));
		memset(m_tx_buffer, 0, TX_BUFFER_SIZE);

		m_service.handle = BLE_GATT_HANDLE_INVALID;

		ble_uuid_t ancs_uuid;
		ancs_uuid.uuid = ANCS_UUID_SERVICE;
		ancs_uuid.type = BLE_UUID_TYPE_VENDOR_BEGIN;

		return ble_db_discovery_evt_register(&ancs_uuid, db_discover_evt_handler);
}


/**@brief Function for creating a TX message for writing a CCCD.
 *
 * @param[in] conn_handle  Connection handle on which to perform the configuration.
 * @param[in] handle_cccd  Handle of the CCCD.
 * @param[in] enable       Enable or disable GATTC notifications.
 *
 * @retval NRF_SUCCESS              If the message was created successfully.
 * @retval NRF_ERROR_INVALID_PARAM  If one of the input parameters was invalid.
 */
static uint32_t cccd_configure(const uint16_t conn_handle, const uint16_t handle_cccd, bool enable)
{
		tx_message_t * p_msg;
		uint16_t       cccd_val = enable ? BLE_CCCD_NOTIFY_BIT_MASK : 0;

		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      = 2;
		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_c_notif_source_notif_enable(const ble_ancs_c_t * p_ancs)
{
		LOG("[ANCS]: Enable Notification Source notifications. writing to handle: %i \n\r",
				m_service.notif_source.handle_cccd);
		return cccd_configure(p_ancs->conn_handle, m_service.notif_source.handle_cccd, true);
}


uint32_t ble_ancs_c_notif_source_notif_disable(const ble_ancs_c_t * p_ancs)
{
		return cccd_configure(p_ancs->conn_handle, m_service.notif_source.handle_cccd, false);
}


uint32_t ble_ancs_c_data_source_notif_enable(const ble_ancs_c_t * p_ancs)
{
		LOG("[ANCS]: Enable Data Source notifications. Writing to handle: %i \n\r",
				m_service.data_source.handle_cccd);
		return cccd_configure(p_ancs->conn_handle, m_service.data_source.handle_cccd, true);
}


uint32_t ble_ancs_c_data_source_notif_disable(const ble_ancs_c_t * p_ancs)
{
		return cccd_configure(p_ancs->conn_handle, m_service.data_source.handle_cccd, false);
}


uint32_t ble_ancs_get_notif_attrs(const ble_ancs_c_t * p_ancs,
																	const uint32_t       p_uid)
{
		tx_message_t * p_msg;
		uint32_t       index                    = 0;
		uint32_t       number_of_requested_attr = 0;

		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.control_point.handle_value;
		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;

		//Encode Command ID.
		p_msg->req.write_req.gattc_value[index++] = BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES;
		
		//Encode Notification UID.
		index += uint32_encode(p_uid, &p_msg->req.write_req.gattc_value[index]);

		//Encode Attribute ID.
		for (uint32_t attr = 0; attr < BLE_ANCS_NB_OF_ATTRS; attr++)
		{
				if (m_ancs_attr_list[attr].get == true)
				{
						p_msg->req.write_req.gattc_value[index++] = attr;
						if ((attr == BLE_ANCS_NOTIF_ATTR_ID_TITLE) ||
								(attr == BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE) ||
								(attr == BLE_ANCS_NOTIF_ATTR_ID_MESSAGE))
						{
								//Encode Length field, only applicable for Title, Subtitle and Message
								index += uint16_encode(m_ancs_attr_list[attr].attr_len,
															&p_msg->req.write_req.gattc_value[index]);
						}
						number_of_requested_attr++;
				}
		}
		p_msg->req.write_req.gattc_params.len = index;
		p_msg->conn_handle                    = p_ancs->conn_handle;
		p_msg->type                           = WRITE_REQ;
		m_expected_number_of_attrs            = number_of_requested_attr;

		tx_buffer_process();

		return NRF_SUCCESS;
}


uint32_t ble_ancs_c_attr_add(const ble_ancs_c_notif_attr_id_values_t id,
														 uint8_t                               * p_data,
														 const uint16_t                          len)
{
		if(p_data == NULL)
		{
				return NRF_ERROR_NULL;
		}
		if((len == 0) || (len > BLE_ANCS_ATTR_DATA_MAX))
		{
				return NRF_ERROR_INVALID_LENGTH;
		}

		m_ancs_attr_list[id].get         = true;
		m_ancs_attr_list[id].attr_len    = len;
		m_ancs_attr_list[id].p_attr_data = p_data;

		return NRF_SUCCESS;
}


uint32_t ble_ancs_c_request_attrs(const ble_ancs_c_evt_notif_t * notif)
{
		uint32_t err_code;
		err_code = ble_ancs_verify_notification_format(notif);
		if (err_code != NRF_SUCCESS)
		{
				return err_code;
		}

		err_code      = ble_ancs_get_notif_attrs(mp_ble_ancs, notif->notif_uid);
		m_parse_state = COMMAND_ID_AND_NOTIF_UID;
		if (err_code != NRF_SUCCESS)
		{
				return err_code;
		}
		return NRF_SUCCESS;
}
Related