Remove unused BLE services.

pull/2234/head
Vincent Coubard 2016-06-17 11:18:24 +01:00
parent 1b826f286b
commit 38671de942
57 changed files with 0 additions and 17893 deletions

View File

@ -1,812 +0,0 @@
/* 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 "ble_err.h"
#include "ble_srv_common.h"
#include "nrf_assert.h"
#include "device_manager.h"
#include "ble_db_discovery.h"
#include "app_error.h"
#include "app_trace.h"
#include "sdk_common.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 ANCS_LOG NRF_LOG_PRINTF_DEBUG /**< 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 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;
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. */
/**@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 Disconnected event received from the SoftDevice.
*
* @details This function check if the disconnect event is happening on the link
* associated with the current instance of the module, if so it will set its
* conn_handle to invalid.
*
* @param[in] p_ancs Pointer to the ANCS client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_disconnected(ble_ancs_c_t * p_ancs, const ble_evt_t * p_ble_evt)
{
if (p_ancs->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
{
p_ancs->conn_handle = BLE_CONN_HANDLE_INVALID;
}
}
void ble_ancs_c_on_db_disc_evt(ble_ancs_c_t * p_ancs, ble_db_discovery_evt_t * p_evt)
{
ANCS_LOG("[ANCS]: Database Discovery handler called with event 0x%x\r\n", p_evt->evt_type);
ble_ancs_c_evt_t evt;
ble_gatt_db_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 == p_ancs->service.service.uuid.type)
{
// Find the handles of the ANCS characteristic.
uint32_t i;
for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
switch (p_chars[i].characteristic.uuid.uuid)
{
case ANCS_UUID_CHAR_CONTROL_POINT:
ANCS_LOG("[ANCS]: Control Point Characteristic found.\n\r");
memcpy(&evt.service.control_point_char,
&p_chars[i].characteristic,
sizeof(ble_gattc_char_t));
break;
case ANCS_UUID_CHAR_DATA_SOURCE:
ANCS_LOG("[ANCS]: Data Source Characteristic found.\n\r");
memcpy(&evt.service.data_source_char,
&p_chars[i].characteristic,
sizeof(ble_gattc_char_t));
evt.service.data_source_cccd.handle = p_chars[i].cccd_handle;
break;
case ANCS_UUID_CHAR_NOTIFICATION_SOURCE:
ANCS_LOG("[ANCS]: Notification point Characteristic found.\n\r");
memcpy(&evt.service.notif_source_char,
&p_chars[i].characteristic,
sizeof(ble_gattc_char_t));
evt.service.notif_source_cccd.handle = p_chars[i].cccd_handle;
break;
default:
break;
}
}
evt.evt_type = BLE_ANCS_C_EVT_DISCOVERY_COMPLETE;
evt.conn_handle = p_evt->conn_handle;
p_ancs->evt_handler(&evt);
}
else
{
evt.evt_type = BLE_ANCS_C_EVT_DISCOVERY_FAILED;
p_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 command id and notification id.
* Used in the @ref parse_get_notif_attrs_response state machine.
*
* @details 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.
*
* @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] index Pointer to an index that helps us keep track of the current data to be parsed.
*
* @return The next parse state.
*/
static ble_ancs_c_parse_state_t command_id_and_notif_parse(ble_ancs_c_t * p_ancs,
const uint8_t * p_data_src,
uint32_t * index)
{
ble_ancs_c_command_id_values_t command_id;
command_id = (ble_ancs_c_command_id_values_t) p_data_src[(*index)++];
if(command_id != BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES)
{
ANCS_LOG("[ANCS]: Invalid Command ID");
return DONE;
}
p_ancs->evt.attr.notif_uid = uint32_decode(&p_data_src[*index]);
*index += sizeof(uint32_t);
return ATTR_ID;
}
/**@brief Function for parsing the id of an iOS attribute.
* Used in the @ref parse_get_notif_attrs_response state machine.
*
* @details We only request attributes that are registered with @ref ble_ancs_c_attr_add
* once they have been reveiced we stop parsing.
*
* @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] index Pointer to an index that helps us keep track of the current data to be parsed.
*
* @return The next parse state.
*/
static ble_ancs_c_parse_state_t attr_id_parse(ble_ancs_c_t * p_ancs,
const uint8_t * p_data_src,
uint32_t * index)
{
p_ancs->evt.attr.attr_id = (ble_ancs_c_notif_attr_id_values_t) p_data_src[(*index)++];
p_ancs->evt.attr.p_attr_data = p_ancs->ancs_attr_list[p_ancs->evt.attr.attr_id].p_attr_data;
if (p_ancs->expected_number_of_attrs == 0)
{
ANCS_LOG("[ANCS]: All requested attributes received\n\r");
// (*index)++;
return DONE;
}
else if (p_ancs->ancs_attr_list[p_ancs->evt.attr.attr_id].get == true)
{
ANCS_LOG("[ANCS]: Attribute ID %i \n\r", p_ancs->evt.attr.attr_id);
return ATTR_LEN1;
}
else
{
p_ancs->expected_number_of_attrs--;
return ATTR_ID;
}
}
/**@brief Function for parsing the length of an iOS attribute.
* Used in the @ref parse_get_notif_attrs_response state machine.
*
* @details The Length is 2 bytes. Since there is a chance we reveice the bytes in two different
* GATTC notifications, we parse only the first byte here and then set the state machine
* ready to parse the next byte.
*
* @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] index Pointer to an index that helps us keep track of the current data to be parsed.
*
* @return The next parse state.
*/
static ble_ancs_c_parse_state_t attr_len1_parse(ble_ancs_c_t * p_ancs, const uint8_t * p_data_src, uint32_t * index)
{
p_ancs->evt.attr.attr_len = p_data_src[(*index)++];
return ATTR_LEN2;
}
/**@brief Function for parsing the length of an iOS attribute.
* Used in the @ref parse_get_notif_attrs_response state machine.
*
* @details Second byte of the length field. If the length is zero, it means that the attribute is not
* present and the state machine is set to parse the next attribute.
*
* @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] index Pointer to an index that helps us keep track of the current data to be parsed.
*
* @return The next parse state.
*/
static ble_ancs_c_parse_state_t attr_len2_parse(ble_ancs_c_t * p_ancs, const uint8_t * p_data_src, uint32_t * index)
{
p_ancs->evt.attr.attr_len |= (p_data_src[(*index)++] << 8);
p_ancs->current_attr_index = 0;
if (p_ancs->evt.attr.attr_len != 0)
{
return ATTR_DATA;
}
else
{
ANCS_LOG("[ANCS]: Attribute LEN %i \n\r", p_ancs->evt.attr.attr_len);
p_ancs->evt.evt_type = BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE;
p_ancs->evt_handler(&p_ancs->evt);
return ATTR_ID;
}
}
/**@brief Function for parsing the data of an iOS attribute.
* Used in the @ref parse_get_notif_attrs_response state machine.
*
* @details Read the data of the attribute into our local buffer.
*
* @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] index Pointer to an index that helps us keep track of the current data to be parsed.
*
* @return The next parse state.
*/
static ble_ancs_c_parse_state_t attr_data_parse(ble_ancs_c_t * p_ancs, const uint8_t * p_data_src, uint32_t * index)
{
// We have not reached the end of the attribute, nor our max allocated internal size.
// Proceed with copying data over to our buffer.
if ( (p_ancs->current_attr_index < p_ancs->ancs_attr_list[p_ancs->evt.attr.attr_id].attr_len)
&& (p_ancs->current_attr_index < p_ancs->evt.attr.attr_len))
{
p_ancs->evt.attr.p_attr_data[p_ancs->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 ( (p_ancs->current_attr_index == p_ancs->evt.attr.attr_len) ||
(p_ancs->current_attr_index == p_ancs->ancs_attr_list[p_ancs->evt.attr.attr_id].attr_len))
{
p_ancs->evt.attr.p_attr_data[p_ancs->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 (p_ancs->current_attr_index < p_ancs->evt.attr.attr_len)
{
(*index) += (p_ancs->evt.attr.attr_len - p_ancs->current_attr_index);
}
ANCS_LOG("[ANCS]: Attribute finished!\n\r");
p_ancs->evt.evt_type = BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE;
p_ancs->evt_handler(&p_ancs->evt);
return ATTR_ID;
}
return ATTR_DATA;
}
/**@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, this function relies on 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 ATTR_ID > LENGTH > DATA > ATTR_ID > LENGTH > DATA until
* we have received all attributes we wanted as a Notification Consumer.
* The Notification Provider can also simply stop sending attributes.
*
* |1 Byte | 4 Bytes |1 Byte |2 Bytes | X Bytes |1 Bytes| 2 Bytes| X Bytes
* +--------+-------------+-------+--------+- - - - - - - - - - +-------+--------+- - - - - - -
* | CMD_ID | NOTIF_UID |ATTR_ID| LENGTH | DATA |ATTR_ID| LENGTH | DATA
* +--------+-------------+-------+--------+- - - - - - - - - - +-------+--------+- - - - - - -
*
* @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)
{
uint32_t index;
for (index = 0; index < hvx_data_len;)
{
switch (p_ancs->parse_state)
{
case COMMAND_ID_AND_NOTIF_UID:
p_ancs->parse_state = command_id_and_notif_parse(p_ancs, p_data_src, &index);
break;
case ATTR_ID:
p_ancs->parse_state = attr_id_parse(p_ancs, p_data_src, &index);
break;
case ATTR_LEN1:
p_ancs->parse_state = attr_len1_parse(p_ancs, p_data_src, &index);
break;
case ATTR_LEN2:
p_ancs->parse_state = attr_len2_parse(p_ancs, p_data_src, &index);
break;
case ATTR_DATA:
p_ancs->parse_state = attr_data_parse(p_ancs, p_data_src, &index);
break;
case DONE:
ANCS_LOG("[ANCS]: State: Done \n\r");
index = hvx_data_len;
break;
default:
// Default case will never trigger intentionally. Go to the DONE state to minimize the consequences.
p_ancs->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_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,
const uint8_t * p_data_src,
const uint16_t hvx_data_len)
{
ble_ancs_c_evt_t ancs_evt;
uint32_t err_code;
if (hvx_data_len != BLE_ANCS_NOTIFICATION_DATA_LENGTH)
{
ancs_evt.evt_type = BLE_ANCS_C_EVT_INVALID_NOTIF;
p_ancs->evt_handler(&ancs_evt);
}
/*lint --e{415} --e{416} -save suppress Warning 415: possible access out of bond */
ancs_evt.notif.evt_id =
(ble_ancs_c_evt_id_values_t) p_data_src[BLE_ANCS_NOTIF_EVT_ID_INDEX];
ancs_evt.notif.evt_flags.silent =
(p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_SILENT) & 0x01;
ancs_evt.notif.evt_flags.important =
(p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_IMPORTANT) & 0x01;
ancs_evt.notif.evt_flags.pre_existing =
(p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_PREEXISTING) & 0x01;
ancs_evt.notif.evt_flags.positive_action =
(p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_POSITIVE_ACTION) & 0x01;
ancs_evt.notif.evt_flags.negative_action =
(p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_NEGATIVE_ACTION) & 0x01;
ancs_evt.notif.category_id =
(ble_ancs_c_category_id_values_t) p_data_src[BLE_ANCS_NOTIF_CATEGORY_ID_INDEX];
ancs_evt.notif.category_count = p_data_src[BLE_ANCS_NOTIF_CATEGORY_CNT_INDEX];
ancs_evt.notif.notif_uid = uint32_decode(&p_data_src[BLE_ANCS_NOTIF_NOTIF_UID]);
/*lint -restore*/
err_code = ble_ancs_verify_notification_format(&ancs_evt.notif);
if (err_code == NRF_SUCCESS)
{
ancs_evt.evt_type = BLE_ANCS_C_EVT_NOTIF;
}
else
{
ancs_evt.evt_type = BLE_ANCS_C_EVT_INVALID_NOTIF;
}
p_ancs->evt_handler(&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_ble_evt->evt.gattc_evt.conn_handle != p_ancs->conn_handle)
{
return;
}
if (p_notif->handle == p_ancs->service.notif_source_char.handle_value)
{
parse_notif(p_ancs, p_notif->data, p_notif->len);
}
else if (p_notif->handle == p_ancs->service.data_source_char.handle_value)
{
parse_get_notif_attrs_response(p_ancs, p_notif->data, p_notif->len);
}
else
{
// No applicable action.
}
}
/**@brief Function for handling write response events.
*
* @param[in] p_ancs_c Pointer to the Battery Service Client Structure.
* @param[in] p_ble_evt Pointer to the SoftDevice event.
*/
static void on_write_rsp(ble_ancs_c_t * p_ancs, const ble_evt_t * p_ble_evt)
{
// Check if the event if on the link for this instance
if (p_ancs->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
{
return;
}
// Check if there is any message to be sent across to the peer and send it.
tx_buffer_process();
}
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_write_rsp(p_ancs, p_ble_evt);
break;
case BLE_GATTC_EVT_HVX:
on_evt_gattc_notif(p_ancs, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnected(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)
{
uint32_t err_code;
//Verify that the parameters needed for to initialize this instance of ANCS are not NULL.
VERIFY_PARAM_NOT_NULL(p_ancs);
VERIFY_PARAM_NOT_NULL(p_ancs_init);
VERIFY_PARAM_NOT_NULL(p_ancs_init->evt_handler);
p_ancs->parse_state = COMMAND_ID_AND_NOTIF_UID;
p_ancs->p_data_dest = NULL;
p_ancs->current_attr_index = 0;
p_ancs->evt_handler = p_ancs_init->evt_handler;
p_ancs->error_handler = p_ancs_init->error_handler;
p_ancs->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ancs->service.data_source_cccd.uuid.uuid = BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG;
p_ancs->service.notif_source_cccd.uuid.uuid = BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG;
// Make sure instance of service is clear. GATT handles inside the service and characteristics are set to @ref BLE_GATT_HANDLE_INVALID.
memset(&p_ancs->service, 0, sizeof(ble_ancs_c_service_t));
memset(m_tx_buffer, 0, TX_BUFFER_SIZE);
// Assign UUID types.
err_code = sd_ble_uuid_vs_add(&ble_ancs_base_uuid128, &p_ancs->service.service.uuid.type);
VERIFY_SUCCESS(err_code);
err_code = sd_ble_uuid_vs_add(&ble_ancs_cp_base_uuid128, &p_ancs->service.control_point_char.uuid.type);
VERIFY_SUCCESS(err_code);
err_code = sd_ble_uuid_vs_add(&ble_ancs_ns_base_uuid128, &p_ancs->service.notif_source_char.uuid.type);
VERIFY_SUCCESS(err_code);
err_code = sd_ble_uuid_vs_add(&ble_ancs_ds_base_uuid128, &p_ancs->service.data_source_char.uuid.type);
VERIFY_SUCCESS(err_code);
// Assign UUID to the service.
p_ancs->service.service.uuid.uuid = ANCS_UUID_SERVICE;
p_ancs->service.service.uuid.type = p_ancs->service.service.uuid.type;
return ble_db_discovery_evt_register(&p_ancs->service.service.uuid);
}
/**@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_16(cccd_val);
p_msg->req.write_req.gattc_value[1] = MSB_16(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)
{
ANCS_LOG("[ANCS]: Enable Notification Source notifications. writing to handle: %i \n\r",
p_ancs->service.notif_source_cccd.handle);
return cccd_configure(p_ancs->conn_handle, p_ancs->service.notif_source_cccd.handle, true);
}
uint32_t ble_ancs_c_notif_source_notif_disable(const ble_ancs_c_t * p_ancs)
{
return cccd_configure(p_ancs->conn_handle, p_ancs->service.notif_source_cccd.handle, false);
}
uint32_t ble_ancs_c_data_source_notif_enable(const ble_ancs_c_t * p_ancs)
{
ANCS_LOG("[ANCS]: Enable Data Source notifications. Writing to handle: %i \n\r",
p_ancs->service.data_source_cccd.handle);
return cccd_configure(p_ancs->conn_handle, p_ancs->service.data_source_cccd.handle, true);
}
uint32_t ble_ancs_c_data_source_notif_disable(const ble_ancs_c_t * p_ancs)
{
return cccd_configure(p_ancs->conn_handle, p_ancs->service.data_source_cccd.handle, false);
}
uint32_t ble_ancs_get_notif_attrs(ble_ancs_c_t * p_ancs,
const uint32_t p_uid)
{
tx_message_t * p_msg;
uint32_t index = 0;
p_ancs->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 = p_ancs->service.control_point_char.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 (p_ancs->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(p_ancs->ancs_attr_list[attr].attr_len,
&p_msg->req.write_req.gattc_value[index]);
}
p_ancs->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;
p_ancs->expected_number_of_attrs = p_ancs->number_of_requested_attr;
tx_buffer_process();
return NRF_SUCCESS;
}
uint32_t ble_ancs_c_attr_add(ble_ancs_c_t * p_ancs,
const ble_ancs_c_notif_attr_id_values_t id,
uint8_t * p_data,
const uint16_t len)
{
VERIFY_PARAM_NOT_NULL(p_data);
if((len == 0) || (len > BLE_ANCS_ATTR_DATA_MAX))
{
return NRF_ERROR_INVALID_LENGTH;
}
p_ancs->ancs_attr_list[id].get = true;
p_ancs->ancs_attr_list[id].attr_len = len;
p_ancs->ancs_attr_list[id].p_attr_data = p_data;
return NRF_SUCCESS;
}
uint32_t ble_ancs_c_request_attrs(ble_ancs_c_t * p_ancs,
const ble_ancs_c_evt_notif_t * p_notif)
{
uint32_t err_code;
err_code = ble_ancs_verify_notification_format(p_notif);
VERIFY_SUCCESS(err_code);
err_code = ble_ancs_get_notif_attrs(p_ancs, p_notif->notif_uid);
p_ancs->parse_state = COMMAND_ID_AND_NOTIF_UID;
VERIFY_SUCCESS(err_code);
return NRF_SUCCESS;
}
uint32_t ble_ancs_c_handles_assign(ble_ancs_c_t * p_ancs,
const uint16_t conn_handle,
const ble_ancs_c_service_t * p_peer_handles)
{
VERIFY_PARAM_NOT_NULL(p_ancs);
p_ancs->conn_handle = conn_handle;
if(p_peer_handles != NULL)
{
p_ancs->service.control_point_char.handle_value = p_peer_handles->control_point_char.handle_value;
p_ancs->service.data_source_cccd.handle = p_peer_handles->data_source_cccd.handle;
p_ancs->service.data_source_char.handle_value = p_peer_handles->data_source_char.handle_value;
p_ancs->service.notif_source_cccd.handle = p_peer_handles->notif_source_cccd.handle;
p_ancs->service.notif_source_char.handle_value = p_peer_handles->notif_source_char.handle_value;
}
return NRF_SUCCESS;
}

View File

@ -1,419 +0,0 @@
/* 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.
*/
/** @file
*
* @defgroup ble_sdk_srv_ancs_c Apple Notification Service client
* @{
* @ingroup ble_sdk_srv
*
* @brief Apple Notification Center Service Client Module.
*
* @details Disclaimer: This client implementation of the Apple Notification Center Service can
* 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.
*
* This module implements the Apple Notification Center Service (ANCS) client.
* This client can be used as a Notification Consumer (NC) that receives data
* notifications from a Notification Provider (NP). The NP is typically an iOS
* device acting as a server. For terminology and up-to-date specs, see
* http://developer.apple.com.
*
* The term "notification" is used in two different meanings:
* - An <i>iOS notification</i> is the data received from the Notification Provider.
* - A <i>GATTC notification</i> is a way to transfer data with <i>Bluetooth</i> Smart.
* In this module, we receive iOS notifications using GATTC notifications.
* We use the full term (iOS notification or GATTC notification) where required to avoid confusion.
*
* Upon initializing the module, you must add the different iOS notification attributes you
* would like to receive for iOS notifications. @ref ble_ancs_c_attr_add.
*
* Once a connection is established with a central device, the module does a service discovery to
* discover the ANVS server handles. If this succeeds (@ref BLE_ANCS_C_EVT_DISCOVERY_COMPLETE)
* The handles for the CTS server are part of the @ref ble_ancs_c_evt_t structure and must be
* assigned to a ANCS_C instance using the @ref ble_ancs_c_handles_assign function. For more
* information about service discovery, see the ble_discovery module documentation
* @ref lib_ble_db_discovery.
*
* The application can now subscribe to iOS notifications using
* @ref ble_ancs_c_notif_source_notif_enable. They arrive in the @ref BLE_ANCS_C_EVT_NOTIF event.
* @ref ble_ancs_c_request_attrs can be used to request attributes for the notifications. They
* arrive in the @ref BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE event.
*
* @msc
* hscale = "1.5";
* Application, ANCS_C;
* |||;
* Application=>ANCS_C [label = "ble_ancs_c_attr_add(attribute)"];
* Application=>ANCS_C [label = "ble_ancs_c_init(ancs_instance, event_handler)"];
* ...;
* Application<<=ANCS_C [label = "BLE_ANCS_C_EVT_DISCOVERY_COMPLETE"];
* Application=>ANCS_C [label = "ble_ancs_c_handles_assign(ancs_instance, conn_handle, service_handles)"];
* Application=>ANCS_C [label = "ble_ancs_c_notif_source_notif_enable(ancs_instance)"];
* Application=>ANCS_C [label = "ble_ancs_c_data_source_notif_enable(ancs_instance)"];
* |||;
* ...;
* |||;
* Application<<=ANCS_C [label = "BLE_ANCS_C_EVT_NOTIF"];
* |||;
* ...;
* |||;
* Application=>ANCS_C [label = "ble_ancs_c_request_attrs(attr_id, buffer)"];
* Application<<=ANCS_C [label = "BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE"];
* |||;
* @endmsc
*
* @note The application must propagate BLE stack events to this module
* by calling ble_ancs_c_on_ble_evt() from the @ref softdevice_handler callback.
*/
#ifndef BLE_ANCS_C_H__
#define BLE_ANCS_C_H__
#include "ble_types.h"
#include "ble_srv_common.h"
#include "device_manager.h"
#include "ble_db_discovery.h"
#define BLE_ANCS_ATTR_DATA_MAX 32 /**< Maximum data length of an iOS notification attribute. */
#define BLE_ANCS_NB_OF_CATEGORY_ID 12 /**< Number of iOS notification categories: Other, Incoming Call, Missed Call, Voice Mail, Social, Schedule, Email, News, Health And Fitness, Business And Finance, Location, Entertainment. */
#define BLE_ANCS_NB_OF_ATTRS 8 /**< Number of iOS notification attributes: AppIdentifier, Title, Subtitle, Message, MessageSize, Date, PositiveActionLabel, NegativeActionLabel. */
#define BLE_ANCS_NB_OF_EVT_ID 3 /**< Number of iOS notification events: Added, Modified, Removed.*/
/** @brief Length of the iOS notification data.
*
* @details 8 bytes:
* Event ID |Event flags |Category ID |Category count|Notification UID
* ---------|------------|------------|--------------|----------------
* 1 byte | 1 byte | 1 byte | 1 byte | 4 bytes
*/
#define BLE_ANCS_NOTIFICATION_DATA_LENGTH 8
#define ANCS_UUID_SERVICE 0xF431 /**< 16-bit service UUID for the Apple Notification Center Service. */
#define ANCS_UUID_CHAR_CONTROL_POINT 0xD8F3 /**< 16-bit control point UUID. */
#define ANCS_UUID_CHAR_DATA_SOURCE 0xC6E9 /**< 16-bit data source UUID. */
#define ANCS_UUID_CHAR_NOTIFICATION_SOURCE 0x120D /**< 16-bit notification source UUID. */
#define BLE_ANCS_EVENT_FLAG_SILENT 0 /**< 0b.......1 Silent: First (LSB) bit is set. All flags can be active at the same time.*/
#define BLE_ANCS_EVENT_FLAG_IMPORTANT 1 /**< 0b......1. Important: Second (LSB) bit is set. All flags can be active at the same time.*/
#define BLE_ANCS_EVENT_FLAG_PREEXISTING 2 /**< 0b.....1.. Pre-existing: Third (LSB) bit is set. All flags can be active at the same time.*/
#define BLE_ANCS_EVENT_FLAG_POSITIVE_ACTION 3 /**< 0b....1... Positive action: Fourth (LSB) bit is set. All flags can be active at the same time.*/
#define BLE_ANCS_EVENT_FLAG_NEGATIVE_ACTION 4 /**< 0b...1.... Negative action: Fifth (LSB) bit is set. All flags can be active at the same time. */
/**@brief Event types that are passed from client to application on an event. */
typedef enum
{
BLE_ANCS_C_EVT_DISCOVERY_COMPLETE, /**< A successful connection has been established and the service was found on the connected peer. */
BLE_ANCS_C_EVT_DISCOVERY_FAILED, /**< It was not possible to discover the service or characteristics of the connected peer. */
BLE_ANCS_C_EVT_NOTIF, /**< An iOS notification was received on the notification source control point. */
BLE_ANCS_C_EVT_INVALID_NOTIF, /**< An iOS notification was received on the notification source control point, but the format is invalid. */
BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE /**< A received iOS notification attribute has been parsed. */
} ble_ancs_c_evt_type_t;
/**@brief Category IDs for iOS notifications. */
typedef enum
{
BLE_ANCS_CATEGORY_ID_OTHER, /**< The iOS notification belongs to the "other" category. */
BLE_ANCS_CATEGORY_ID_INCOMING_CALL, /**< The iOS notification belongs to the "Incoming Call" category. */
BLE_ANCS_CATEGORY_ID_MISSED_CALL, /**< The iOS notification belongs to the "Missed Call" category. */
BLE_ANCS_CATEGORY_ID_VOICE_MAIL, /**< The iOS notification belongs to the "Voice Mail" category. */
BLE_ANCS_CATEGORY_ID_SOCIAL, /**< The iOS notification belongs to the "Social" category. */
BLE_ANCS_CATEGORY_ID_SCHEDULE, /**< The iOS notification belongs to the "Schedule" category. */
BLE_ANCS_CATEGORY_ID_EMAIL, /**< The iOS notification belongs to the "E-mail" category. */
BLE_ANCS_CATEGORY_ID_NEWS, /**< The iOS notification belongs to the "News" category. */
BLE_ANCS_CATEGORY_ID_HEALTH_AND_FITNESS, /**< The iOS notification belongs to the "Health and Fitness" category. */
BLE_ANCS_CATEGORY_ID_BUSINESS_AND_FINANCE, /**< The iOS notification belongs to the "Buisness and Finance" category. */
BLE_ANCS_CATEGORY_ID_LOCATION, /**< The iOS notification belongs to the "Location" category. */
BLE_ANCS_CATEGORY_ID_ENTERTAINMENT /**< The iOS notification belongs to the "Entertainment" category. */
} ble_ancs_c_category_id_values_t;
/**@brief Event IDs for iOS notifications. */
typedef enum
{
BLE_ANCS_EVENT_ID_NOTIFICATION_ADDED, /**< The iOS notification was added. */
BLE_ANCS_EVENT_ID_NOTIFICATION_MODIFIED, /**< The iOS notification was modified. */
BLE_ANCS_EVENT_ID_NOTIFICATION_REMOVED /**< The iOS notification was removed. */
} ble_ancs_c_evt_id_values_t;
/**@brief Control point command IDs that the Notification Consumer can send to the Notification Provider. */
typedef enum
{
BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES, /**< Requests attributes to be sent from the NP to the NC for a given notification. */
BLE_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES, /**< Requests attributes to be sent from the NP to the NC for a given iOS App. */
BLE_ANCS_COMMAND_ID_GET_PERFORM_NOTIF_ACTION, /**< Requests an action to be performed on a given notification, for example dismiss an alarm. */
} ble_ancs_c_command_id_values_t;
/**@brief IDs for iOS notification attributes. */
typedef enum
{
BLE_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER, /**< Identifies that the attribute data is of an "App Identifier" type. */
BLE_ANCS_NOTIF_ATTR_ID_TITLE, /**< Identifies that the attribute data is a "Title". */
BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE, /**< Identifies that the attribute data is a "Subtitle". */
BLE_ANCS_NOTIF_ATTR_ID_MESSAGE, /**< Identifies that the attribute data is a "Message". */
BLE_ANCS_NOTIF_ATTR_ID_MESSAGE_SIZE, /**< Identifies that the attribute data is a "Message Size". */
BLE_ANCS_NOTIF_ATTR_ID_DATE, /**< Identifies that the attribute data is a "Date". */
BLE_ANCS_NOTIF_ATTR_ID_POSITIVE_ACTION_LABEL, /**< The notification has a "Positive action" that can be executed associated with it. */
BLE_ANCS_NOTIF_ATTR_ID_NEGATIVE_ACTION_LABEL, /**< The notification has a "Negative action" that can be executed associated with it. */
} ble_ancs_c_notif_attr_id_values_t;
/**@brief Flags for iOS notifications. */
typedef struct
{
uint8_t silent : 1; /**< If this flag is set, the notification has a low priority. */
uint8_t important : 1; /**< If this flag is set, the notification has a high priority. */
uint8_t pre_existing : 1; /**< If this flag is set, the notification is pre-existing. */
uint8_t positive_action : 1; /**< If this flag is set, the notification has a positive action that can be taken. */
uint8_t negative_action : 1; /**< If this flag is set, the notification has a negative action that can be taken. */
} ble_ancs_c_notif_flags_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;
/**@brief iOS notification structure. */
typedef struct
{
ble_ancs_c_evt_id_values_t evt_id; /**< Whether the notification was added, removed, or modified. */
ble_ancs_c_notif_flags_t evt_flags; /**< Bitmask to signal if a special condition applies to the notification, for example, "Silent" or "Important". */
ble_ancs_c_category_id_values_t category_id; /**< Classification of the notification type, for example, email or location. */
uint8_t category_count; /**< Current number of active notifications for this category ID. */
uint32_t notif_uid; /**< Notification UID. */
} ble_ancs_c_evt_notif_t;
/**@brief iOS notification attribute structure for incomming attributes. */
typedef struct
{
uint32_t notif_uid; /**< UID of the notification that the attribute belongs to.*/
uint16_t attr_len; /**< Length of the received attribute data. */
ble_ancs_c_notif_attr_id_values_t attr_id; /**< Classification of the attribute type, for example, title or date. */
uint8_t * p_attr_data; /**< Pointer to where the memory is allocated for storing incoming attributes. */
} ble_ancs_c_evt_notif_attr_t;
/**@brief iOS notification attribute content wanted by our application. */
typedef struct
{
bool get; /**< Boolean to determine if this attribute will be requested from the Notification Provider. */
ble_ancs_c_notif_attr_id_values_t attr_id; /**< Attribute ID: AppIdentifier(0), Title(1), Subtitle(2), Message(3), MessageSize(4), Date(5), PositiveActionLabel(6), NegativeActionLabel(7). */
uint16_t attr_len; /**< Length of the attribute. If more data is received from the Notification Provider, all data beyond this length is discarded. */
uint8_t * p_attr_data; /**< Pointer to where the memory is allocated for storing incoming attributes. */
} ble_ancs_c_attr_list_t;
/**@brief Structure used for holding the Apple Notification Center Service found during the
discovery process.
*/
typedef struct
{
ble_gattc_service_t service; /**< The GATT Service holding the discovered Apple Notification Center Service. (0xF431). */
ble_gattc_char_t control_point_char; /**< ANCS Control Point Characteristic. Allows interaction with the peer (0xD8F3). */
ble_gattc_char_t notif_source_char; /**< ANCS Notification Source Characteristic. Keeps track of arrival, modification, and removal of notifications (0x120D). */
ble_gattc_desc_t notif_source_cccd; /**< ANCS Notification Source Characteristic Descriptor. Enables or Disables GATT notifications */
ble_gattc_char_t data_source_char; /**< ANCS Data Source Characteristic, where attribute data for the notifications is received from peer (0xC6E9). */
ble_gattc_desc_t data_source_cccd; /**< ANCS Data Source Characteristic Descriptor. Enables or Disables GATT notifications */
} ble_ancs_c_service_t;
/**@brief ANCS client module event structure.
*
* @details The structure contains the event that should be handled by the main application.
*/
typedef struct
{
ble_ancs_c_evt_type_t evt_type; /**< Type of event.*/
uint16_t conn_handle; /**< Connection handle on which the ANCS service was discovered on the peer device. This will be filled if the evt_type is @ref BLE_ANCS_C_EVT_DISCOVERY_COMPLETE.*/
ble_ancs_c_evt_notif_t notif; /**< iOS notification. Will be filled if evt_type is @ref BLE_ANCS_C_EVT_NOTIF. */
ble_ancs_c_evt_notif_attr_t attr; /**< Currently received attribute for a given notification. Will be filled if the evt_type is @ref BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE. */
ble_ancs_c_service_t service; /**< Info on the discovered Alert Notification Service discovered. This will be filled if the evt_type is @ref BLE_ANCS_C_EVT_DISCOVERY_COMPLETE.*/
uint32_t error_code; /**< Additional status or error code if the event was caused by a stack error or GATT status, for example, during service discovery. */
} ble_ancs_c_evt_t;
/**@brief iOS notification event handler type. */
typedef void (*ble_ancs_c_evt_handler_t) (ble_ancs_c_evt_t * p_evt);
/**@brief iOS notification structure, which contains various status information for the client. */
typedef struct
{
ble_ancs_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Apple Notification client application. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
uint16_t conn_handle; /**< Handle of the current connection. Set with @ref ble_ancs_c_handles_assign when connected. */
ble_ancs_c_service_t service; /**< Struct to store the different handles and UUIDs related to the service. */
ble_ancs_c_attr_list_t 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. */
uint32_t number_of_requested_attr; /**< The number of attributes that will be requested upon a iOS notification attribute request is made. */
uint32_t expected_number_of_attrs; /**< The number of attributes expected upon receiving attributes. Keeps track of when to stop reading incoming attributes. */
ble_ancs_c_parse_state_t parse_state; /**< ANCS notification attribute parsing state. */
uint8_t * p_data_dest; /**< Attribute that the parsed data will be copied into. */
uint16_t current_attr_index; /**< Variable to keep track of how much (for a given attribute) we are done parsing. */
ble_ancs_c_evt_t evt; /**< The event is filled with several iteration of the parse_get_notif_attrs_response function when requesting iOS notification attributes. So we must allocate memory for it here.*/
} ble_ancs_c_t;
/**@brief Apple Notification client init structure, which contains all options and data needed for
* initialization of the client.*/
typedef struct
{
ble_ancs_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Battery Service. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
} ble_ancs_c_init_t;
/**@brief Apple Notification Center Service UUIDs. */
extern const ble_uuid128_t ble_ancs_base_uuid128; /**< Service UUID. */
extern const ble_uuid128_t ble_ancs_cp_base_uuid128; /**< Control point UUID. */
extern const ble_uuid128_t ble_ancs_ns_base_uuid128; /**< Notification source UUID. */
extern const ble_uuid128_t ble_ancs_ds_base_uuid128; /**< Data source UUID. */
/**@brief Function for handling the application's BLE Stack events.
*
* @details Handles all events from the BLE stack that are of interest to the ANCS client.
*
* @param[in] p_ancs ANCS client structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_ancs_c_on_ble_evt(ble_ancs_c_t * p_ancs, const ble_evt_t * p_ble_evt);
/**@brief Function for handling events from the database discovery module.
*
* @details This function will handle an event from the database discovery module, and determine
* if it relates to the discovery of ANCS at the peer. If so, it will
* call the application's event handler indicating that ANCS 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_ancs Pointer to the ANCS client structure.
* @param[in] p_evt Pointer to the event received from the database discovery module.
*/
void ble_ancs_c_on_db_disc_evt(ble_ancs_c_t * p_ancs, ble_db_discovery_evt_t * p_evt);
/**@brief Function for initializing the ANCS client.
*
* @param[out] p_ancs ANCS client structure. This structure must be
* supplied by the application. It is initialized by this function
* and will later be used to identify this particular client instance.
* @param[in] p_ancs_init Information needed to initialize the client.
*
* @retval NRF_SUCCESS If the client was initialized successfully. Otherwise, an error code is returned.
*/
uint32_t ble_ancs_c_init(ble_ancs_c_t * p_ancs, const ble_ancs_c_init_t * p_ancs_init);
/**@brief Function for writing to the CCCD to enable notifications from the Apple Notification Service.
*
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
* the application. It identifies the particular client instance to use.
*
* @retval NRF_SUCCESS If writing to the CCCD was successful. Otherwise, an error code is returned.
*/
uint32_t ble_ancs_c_notif_source_notif_enable(const ble_ancs_c_t * p_ancs);
/**@brief Function for writing to the CCCD to enable data source notifications from the ANCS.
*
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
* the application. It identifies the particular client instance to use.
*
* @retval NRF_SUCCESS If writing to the CCCD was successful. Otherwise, an error code is returned.
*/
uint32_t ble_ancs_c_data_source_notif_enable(const ble_ancs_c_t * p_ancs);
/**@brief Function for writing to the CCCD to disable notifications from the ANCS.
*
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
* the application. It identifies the particular client instance to use.
*
* @retval NRF_SUCCESS If writing to the CCCD was successful. Otherwise, an error code is returned.
*/
uint32_t ble_ancs_c_notif_source_notif_disable(const ble_ancs_c_t * p_ancs);
/**@brief Function for writing to the CCCD to disable data source notifications from the ANCS.
*
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
* the application. It identifies the particular client instance to use.
*
* @retval NRF_SUCCESS If writing to the CCCD was successful. Otherwise, an error code is returned.
*/
uint32_t ble_ancs_c_data_source_notif_disable(const ble_ancs_c_t * p_ancs);
/**@brief Function for registering attributes that will be requested if ble_ancs_c_request_attrs
* is called.
*
* @param[in] p_ancs ANCS client instance on which the attribute will be registered.
* @param[in] id ID of the attribute that will be added.
* @param[in] p_data Pointer to a buffer where the data of the attribute can be stored.
* @param[in] len Length of the buffer where the data of the attribute can be stored.
* @retval NRF_SUCCESS If all operations were successful. Otherwise, an error code is returned.
*/
uint32_t ble_ancs_c_attr_add(ble_ancs_c_t * p_ancs,
const ble_ancs_c_notif_attr_id_values_t id,
uint8_t * p_data,
const uint16_t len);
/**@brief Function for requesting attributes for a notification.
*
* @param[in] p_ancs iOS notification structure. This structure must be supplied by
* the application. It identifies the particular client instance to use.
* @param[in] p_notif Pointer to the notification whose attributes will be requested from
* the Notification Provider.
*
* @retval NRF_SUCCESS If all operations were successful. Otherwise, an error code is returned.
*/
uint32_t ble_ancs_c_request_attrs(ble_ancs_c_t * p_ancs,
const ble_ancs_c_evt_notif_t * p_notif);
/**@brief Function for assigning handle to a this instance of ancs_c.
*
* @details Call this function when a link has been established with a peer to
* associate this link to this instance of the module. This makes it
* possible to handle several link and associate each link to a particular
* instance of this module. The connection handle and attribute handles will be
* provided from the discovery event @ref BLE_ANCS_C_EVT_DISCOVERY_COMPLETE.
*
* @param[in] p_ancs Pointer to the ANCS client structure instance to associate with these
* handles.
* @param[in] conn_handle Connection handle to associated with the given ANCS Instance.
* @param[in] p_service Attribute handles on the ANCS server that you want this ANCS client to
* interact with.
*
* @retval NRF_SUCCESS If the operation was successful.
* @retval NRF_ERROR_NULL If a p_ancs was a NULL pointer.
*/
uint32_t ble_ancs_c_handles_assign(ble_ancs_c_t * p_ancs, const uint16_t conn_handle, const ble_ancs_c_service_t * p_service);
#endif // BLE_ANCS_C_H__
/** @} */

View File

@ -1,544 +0,0 @@
/* 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.
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#include "ble_ans_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 "ble_db_discovery.h"
#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. */
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. */
} ans_tx_request_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 central.
*/
typedef struct
{
uint16_t conn_handle; /**< Connection handle to be used when transmitting this message. */
ans_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 central. */
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. */
/**@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 copying a characteristic.
*/
static void char_set(ble_gattc_char_t * p_dest_char, const ble_gattc_char_t * p_source_char)
{
memcpy(p_dest_char, p_source_char, sizeof(ble_gattc_char_t));
}
static void char_cccd_set(ble_gattc_desc_t * p_cccd, const uint16_t cccd_handle)
{
p_cccd->handle = cccd_handle;
}
/** @brief Function to check that all handles required by the client to use the server are present.
*/
static bool is_valid_ans_srv_discovered(const ble_ans_c_service_t * p_srv)
{
if ((p_srv->alert_notif_ctrl_point.handle_value == BLE_GATT_HANDLE_INVALID) ||
(p_srv->suported_new_alert_cat.handle_value == BLE_GATT_HANDLE_INVALID) ||
(p_srv->suported_unread_alert_cat.handle_value == BLE_GATT_HANDLE_INVALID) ||
(p_srv->new_alert.handle_value == BLE_GATT_HANDLE_INVALID) ||
(p_srv->unread_alert_status.handle_value == BLE_GATT_HANDLE_INVALID) ||
(p_srv->new_alert_cccd.handle == BLE_GATT_HANDLE_INVALID) ||
(p_srv->unread_alert_cccd.handle == BLE_GATT_HANDLE_INVALID)
)
{
// At least one required characteristic is missing on the server side.
return false;
}
return true;
}
void ble_ans_c_on_db_disc_evt(ble_ans_c_t * p_ans, const ble_db_discovery_evt_t * p_evt)
{
ble_ans_c_evt_t evt;
memset(&evt, 0, sizeof(ble_ans_c_evt_t));
evt.conn_handle = p_evt->conn_handle;
evt.evt_type = BLE_ANS_C_EVT_DISCOVERY_FAILED;
// Check if the Alert Notification Service was discovered.
if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE
&&
p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_ALERT_NOTIFICATION_SERVICE
&&
p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
{
// Find the characteristics inside the service.
for (uint8_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
const ble_gatt_db_char_t * p_char = &(p_evt->params.discovered_db.charateristics[i]);
switch (p_char->characteristic.uuid.uuid)
{
case BLE_UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR:
NRF_LOG_PRINTF("[ANS] Found Ctrlpt \n\r");
char_set(&evt.data.service.alert_notif_ctrl_point, &p_char->characteristic);
break;
case BLE_UUID_UNREAD_ALERT_CHAR:
NRF_LOG_PRINTF("[ANS] Found Unread Alert \n\r");
char_set(&evt.data.service.unread_alert_status, &p_char->characteristic);
char_cccd_set(&evt.data.service.unread_alert_cccd,
p_char->cccd_handle);
break;
case BLE_UUID_NEW_ALERT_CHAR:
NRF_LOG_PRINTF("[ANS] Found New Alert \n\r");
char_set(&evt.data.service.new_alert, &p_char->characteristic);
char_cccd_set(&evt.data.service.new_alert_cccd,
p_char->cccd_handle);
break;
case BLE_UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR:
NRF_LOG_PRINTF("[ANS] Found supported unread alert category \n\r");
char_set(&evt.data.service.suported_unread_alert_cat, &p_char->characteristic);
break;
case BLE_UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR:
NRF_LOG_PRINTF("[ANS] Found supported new alert category \n\r");
char_set(&evt.data.service.suported_new_alert_cat, &p_char->characteristic);
break;
default:
// No implementation needed.
break;
}
}
if (is_valid_ans_srv_discovered(&evt.data.service))
{
evt.evt_type = BLE_ANS_C_EVT_DISCOVERY_COMPLETE;
}
}
p_ans->evt_handler(&evt);
}
/**@brief Function for receiving and validating notifications received from the central.
*/
static void event_notify(ble_ans_c_t * p_ans, const ble_evt_t * p_ble_evt)
{
uint32_t message_length;
ble_ans_c_evt_t event;
ble_ans_alert_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_ANS_C_EVT_NOTIFICATION;
if (p_notification->len < NOTIFICATION_DATA_LENGTH)
{
return;
}
message_length = p_notification->len - NOTIFICATION_DATA_LENGTH;
if (p_notification->handle == p_ans->service.new_alert.handle_value)
{
BLE_UUID_COPY_INST(event.uuid, p_ans->service.new_alert.uuid);
}
else if (p_notification->handle == p_ans->service.unread_alert_status.handle_value)
{
BLE_UUID_COPY_INST(event.uuid, p_ans->service.unread_alert_status.uuid);
}
else
{
// Nothing to process.
return;
}
p_alert->alert_category = p_notification->data[0];
p_alert->alert_category_count = p_notification->data[1]; //lint !e415
p_alert->alert_msg_length = (message_length > p_ans->message_buffer_size)
? p_ans->message_buffer_size
: message_length;
p_alert->p_alert_msg_buf = p_ans->p_message_buffer;
memcpy(p_alert->p_alert_msg_buf,
&p_notification->data[NOTIFICATION_DATA_LENGTH],
p_alert->alert_msg_length); //lint !e416
p_ans->evt_handler(&event);
}
/**@brief Function for handling write response events.
*/
static void event_write_rsp(ble_ans_c_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_ans_c_t * p_ans, const ble_evt_t * p_ble_evt)
{
ble_ans_c_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_ANS_C_EVT_READ_RESP;
if (p_response->len < READ_DATA_LENGTH_MIN)
{
tx_buffer_process();
return;
}
if (p_response->handle == p_ans->service.suported_new_alert_cat.handle_value)
{
BLE_UUID_COPY_INST(event.uuid, p_ans->service.suported_new_alert_cat.uuid);
}
else if (p_response->handle == p_ans->service.suported_unread_alert_cat.handle_value)
{
BLE_UUID_COPY_INST(event.uuid, p_ans->service.suported_unread_alert_cat.uuid);
}
else
{
// Bad response, ignore.
tx_buffer_process();
return;
}
event.data.settings = *(ble_ans_alert_settings_t *)(p_response->data);
if (p_response->len == READ_DATA_LENGTH_MIN)
{
// Those must default to 0, if they are not returned by central.
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_ans_c_t * p_ans, ble_evt_t const * p_ble_evt)
{
if (p_ans->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
{
p_ans->conn_handle = BLE_CONN_HANDLE_INVALID;
// Clearing all data for the service will also set all handle values to @ref BLE_GATT_HANDLE_INVALID
memset(&p_ans->service, 0, sizeof(ble_ans_c_service_t));
// There was a valid instance of IAS on the peer. Send an event to the
// application, so that it can do any clean up related to this module.
ble_ans_c_evt_t evt;
evt.evt_type = BLE_ANS_C_EVT_DISCONN_COMPLETE;
p_ans->evt_handler(&evt);
}
}
/**@brief Function for handling of BLE stack events.
*/
void ble_ans_c_on_ble_evt(ble_ans_c_t * p_ans, const ble_evt_t * p_ble_evt)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GATTC_EVT_HVX:
event_notify(p_ans, p_ble_evt);
break;
case BLE_GATTC_EVT_WRITE_RSP:
event_write_rsp(p_ans, p_ble_evt);
break;
case BLE_GATTC_EVT_READ_RSP:
event_read_rsp(p_ans, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
event_disconnect(p_ans, p_ble_evt);
break;
}
}
uint32_t ble_ans_c_init(ble_ans_c_t * p_ans, const ble_ans_c_init_t * p_ans_init)
{
VERIFY_PARAM_NOT_NULL(p_ans);
VERIFY_PARAM_NOT_NULL(p_ans_init);
VERIFY_PARAM_NOT_NULL(p_ans_init->evt_handler);
// clear all handles
memset(p_ans, 0, sizeof(ble_ans_c_t));
memset(m_tx_buffer, 0, TX_BUFFER_SIZE);
p_ans->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ans->evt_handler = p_ans_init->evt_handler;
p_ans->error_handler = p_ans_init->error_handler;
p_ans->message_buffer_size = p_ans_init->message_buffer_size;
p_ans->p_message_buffer = p_ans_init->p_message_buffer;
BLE_UUID_BLE_ASSIGN(p_ans->service.service.uuid, BLE_UUID_ALERT_NOTIFICATION_SERVICE);
BLE_UUID_BLE_ASSIGN(p_ans->service.new_alert.uuid, BLE_UUID_NEW_ALERT_CHAR);
BLE_UUID_BLE_ASSIGN(p_ans->service.alert_notif_ctrl_point.uuid,
BLE_UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR);
BLE_UUID_BLE_ASSIGN(p_ans->service.unread_alert_status.uuid, BLE_UUID_UNREAD_ALERT_CHAR);
BLE_UUID_BLE_ASSIGN(p_ans->service.suported_new_alert_cat.uuid,
BLE_UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR);
BLE_UUID_BLE_ASSIGN(p_ans->service.suported_unread_alert_cat.uuid,
BLE_UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR);
BLE_UUID_BLE_ASSIGN(p_ans->service.new_alert_cccd.uuid, BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG);
BLE_UUID_BLE_ASSIGN(p_ans->service.unread_alert_cccd.uuid,
BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG);
return ble_db_discovery_evt_register(&p_ans->service.service.uuid);
}
/**@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_GATT_HVX_NOTIFICATION : 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 = 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_16(cccd_val);
p_msg->req.write_req.gattc_value[1] = MSB_16(cccd_val);
p_msg->conn_handle = conn_handle;
p_msg->type = WRITE_REQ;
tx_buffer_process();
return NRF_SUCCESS;
}
uint32_t ble_ans_c_enable_notif_new_alert(const ble_ans_c_t * p_ans)
{
if (p_ans->conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
else
{
return cccd_configure(p_ans->conn_handle,
p_ans->service.new_alert_cccd.handle,
true);
}
}
uint32_t ble_ans_c_disable_notif_new_alert(const ble_ans_c_t * p_ans)
{
return cccd_configure(p_ans->conn_handle,
p_ans->service.new_alert_cccd.handle,
false);
}
uint32_t ble_ans_c_enable_notif_unread_alert(const ble_ans_c_t * p_ans)
{
if ( p_ans->conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
return cccd_configure(p_ans->conn_handle,
p_ans->service.unread_alert_cccd.handle,
true);
}
uint32_t ble_ans_c_disable_notif_unread_alert(const ble_ans_c_t * p_ans)
{
return cccd_configure(p_ans->conn_handle,
p_ans->service.unread_alert_cccd.handle,
false);
}
uint32_t ble_ans_c_control_point_write(const ble_ans_c_t * p_ans,
const ble_ans_control_point_t * p_control_point)
{
tx_message_t * p_msg;
p_msg = &m_tx_buffer[m_tx_insert_index++];
m_tx_insert_index &= TX_BUFFER_MASK;
p_msg->req.write_req.gattc_params.handle = p_ans->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;
}
uint32_t ble_ans_c_new_alert_read(const ble_ans_c_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 = p_ans->service.suported_new_alert_cat.handle_value;
msg->conn_handle = p_ans->conn_handle;
msg->type = READ_REQ;
tx_buffer_process();
return NRF_SUCCESS;
}
uint32_t ble_ans_c_unread_alert_read(const ble_ans_c_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 = p_ans->service.suported_unread_alert_cat.handle_value;
msg->conn_handle = p_ans->conn_handle;
msg->type = READ_REQ;
tx_buffer_process();
return NRF_SUCCESS;
}
uint32_t ble_ans_c_new_alert_notify(const ble_ans_c_t * p_ans, ble_ans_category_id_t category_id)
{
ble_ans_control_point_t control_point;
control_point.command = ANS_NOTIFY_NEW_INCOMING_ALERT_IMMEDIATELY;
control_point.category = category_id;
return ble_ans_c_control_point_write(p_ans, &control_point);
}
uint32_t ble_ans_c_unread_alert_notify(const ble_ans_c_t * p_ans, ble_ans_category_id_t category_id)
{
ble_ans_control_point_t control_point;
control_point.command = ANS_NOTIFY_UNREAD_CATEGORY_STATUS_IMMEDIATELY;
control_point.category = category_id;
return ble_ans_c_control_point_write(p_ans, &control_point);
}
uint32_t ble_ans_c_handles_assign(ble_ans_c_t * p_ans,
const uint16_t conn_handle,
const ble_ans_c_service_t * p_peer_handles)
{
VERIFY_PARAM_NOT_NULL(p_ans);
if (!is_valid_ans_srv_discovered(p_peer_handles))
{
return NRF_ERROR_INVALID_PARAM;
}
p_ans->conn_handle = conn_handle;
if (p_peer_handles != NULL)
{
// Copy the handles from the discovered characteristics over to the provided client instance.
char_set(&p_ans->service.alert_notif_ctrl_point, &p_peer_handles->alert_notif_ctrl_point);
char_set(&p_ans->service.suported_new_alert_cat, &p_peer_handles->suported_new_alert_cat);
char_set(&p_ans->service.suported_unread_alert_cat, &p_peer_handles->suported_unread_alert_cat);
char_set(&p_ans->service.new_alert, &p_peer_handles->new_alert);
char_cccd_set(&p_ans->service.new_alert_cccd, p_peer_handles->new_alert_cccd.handle);
char_set(&p_ans->service.unread_alert_status, &p_peer_handles->unread_alert_status);
char_cccd_set(&p_ans->service.unread_alert_cccd, p_peer_handles->unread_alert_cccd.handle);
}
return NRF_SUCCESS;
}

View File

@ -1,348 +0,0 @@
/* 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.
*/
/** @file
*
* @defgroup ble_sdk_srv_ans_c Alert Notification Service Client
* @{
* @ingroup ble_sdk_srv
* @brief Alert Notification module.
*
* @details This module implements the Alert Notification Client according to the
* Alert Notification Profile.
*
* @note The application must propagate BLE stack events to the Alert Notification Client module
* by calling ble_ans_c_on_ble_evt() from the @ref softdevice_handler callback.
*
* @note Attention!
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_ANS_C_H__
#define BLE_ANS_C_H__
#include "ble.h"
#include "ble_gatts.h"
#include "ble_types.h"
#include "sdk_common.h"
#include "ble_srv_common.h"
#include "ble_db_discovery.h"
// Forward declaration of the ble_ans_c_t type.
typedef struct ble_ans_c_s ble_ans_c_t;
/** Alerts types as defined in the alert category id; UUID: 0x2A43. */
typedef enum
{
ANS_TYPE_SIMPLE_ALERT = 0, /**< General text alert or non-text alert.*/
ANS_TYPE_EMAIL = 1, /**< Alert when email messages arrives.*/
ANS_TYPE_NEWS = 2, /**< News feeds such as RSS, Atom.*/
ANS_TYPE_NOTIFICATION_CALL = 3, /**< Incoming call.*/
ANS_TYPE_MISSED_CALL = 4, /**< Missed call.*/
ANS_TYPE_SMS_MMS = 5, /**< SMS/MMS message arrives.*/
ANS_TYPE_VOICE_MAIL = 6, /**< Voice mail.*/
ANS_TYPE_SCHEDULE = 7, /**< Alert occurred on calendar, planner.*/
ANS_TYPE_HIGH_PRIORITIZED_ALERT = 8, /**< Alert that should be handled as high priority.*/
ANS_TYPE_INSTANT_MESSAGE = 9, /**< Alert for incoming instant messages.*/
ANS_TYPE_ALL_ALERTS = 0xFF /**< Identifies All Alerts. */
} ble_ans_category_id_t;
/** Alerts notification control point commands as defined in the Alert Notification Specification;
* UUID: 0x2A44.
*/
typedef enum
{
ANS_ENABLE_NEW_INCOMING_ALERT_NOTIFICATION = 0, /**< Enable New Incoming Alert Notification.*/
ANS_ENABLE_UNREAD_CATEGORY_STATUS_NOTIFICATION = 1, /**< Enable Unread Category Status Notification.*/
ANS_DISABLE_NEW_INCOMING_ALERT_NOTIFICATION = 2, /**< Disable New Incoming Alert Notification.*/
ANS_DISABLE_UNREAD_CATEGORY_STATUS_NOTIFICATION = 3, /**< Disable Unread Category Status Notification.*/
ANS_NOTIFY_NEW_INCOMING_ALERT_IMMEDIATELY = 4, /**< Notify New Incoming Alert immediately.*/
ANS_NOTIFY_UNREAD_CATEGORY_STATUS_IMMEDIATELY = 5, /**< Notify Unread Category Status immediately.*/
} ble_ans_command_id_t;
/**@brief Alert Notification Event types that are passed from client to application on an event. */
typedef enum
{
BLE_ANS_C_EVT_DISCOVERY_COMPLETE, /**< A successful connection has been established and the characteristics of the server has been fetched. */
BLE_ANS_C_EVT_DISCOVERY_FAILED, /**< It was not possible to discover service or characteristics of the connected peer. */
BLE_ANS_C_EVT_DISCONN_COMPLETE, /**< The connection has been taken down. */
BLE_ANS_C_EVT_NOTIFICATION, /**< A valid Alert Notification has been received from the server.*/
BLE_ANS_C_EVT_READ_RESP, /**< A read response has been received from the server.*/
BLE_ANS_C_EVT_WRITE_RESP /**< A write response has been received from the server.*/
} ble_ans_c_evt_type_t;
/**@brief Alert Notification Control Point structure. */
typedef struct
{
ble_ans_command_id_t command; /**< The command to be written to the control point, see @ref ble_ans_command_id_t. */
ble_ans_category_id_t category; /**< The category for the control point for which the command applies, see @ref ble_ans_category_id_t. */
} ble_ans_control_point_t;
/**@brief Alert Notification Setting structure containing the supported alerts in the service.
*
*@details
* The structure contains bit fields describing which alerts that are supported:
* 0 = Unsupported
* 1 = Supported
*/
typedef struct
{
uint8_t ans_simple_alert_support : 1; /**< Support for General text alert or non-text alert.*/
uint8_t ans_email_support : 1; /**< Support for Alert when email messages arrives.*/
uint8_t ans_news_support : 1; /**< Support for News feeds such as RSS, Atom.*/
uint8_t ans_notification_call_support : 1; /**< Support for Incoming call.*/
uint8_t ans_missed_call_support : 1; /**< Support for Missed call.*/
uint8_t ans_sms_mms_support : 1; /**< Support for SMS/MMS message arrives.*/
uint8_t ans_voice_mail_support : 1; /**< Support for Voice mail.*/
uint8_t ans_schedule_support : 1; /**< Support for Alert occurred on calendar, planner.*/
uint8_t ans_high_prioritized_alert_support : 1; /**< Support for Alert that should be handled as high priority.*/
uint8_t ans_instant_message_support : 1; /**< Support for Alert for incoming instant messages.*/
uint8_t reserved : 6; /**< Reserved for future use. */
} ble_ans_alert_settings_t;
/**@brief Alert Notification structure
*/
typedef struct
{
uint8_t alert_category; /**< Alert category to which this alert belongs.*/
uint8_t alert_category_count; /**< Number of alerts in the category. */
uint32_t alert_msg_length; /**< Length of optional text message send by the server. */
uint8_t * p_alert_msg_buf; /**< Pointer to buffer containing the optional text message. */
} ble_ans_alert_notification_t;
/**@brief Struct to hold information on the Alert Notification Service if found on the server.
*/
typedef struct
{
ble_gattc_service_t service; /**< The GATT service holding the discovered Alert Notification Service. */
ble_gattc_char_t alert_notif_ctrl_point; /**< Characteristic for the Alert Notification Control Point. @ref BLE_UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR */
ble_gattc_char_t suported_new_alert_cat; /**< Characteristic for the Supported New Alert category. @ref BLE_UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR */
ble_gattc_char_t suported_unread_alert_cat; /**< Characteristic for the Unread Alert category. @ref BLE_UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR */
ble_gattc_char_t new_alert; /**< Characteristic for the New Alert Notification. @ref BLE_UUID_NEW_ALERT_CHAR */
ble_gattc_desc_t new_alert_cccd; /**< Characteristic Descriptor for New Alert Category. Enables or Disables GATT notifications */
ble_gattc_char_t unread_alert_status; /**< Characteristic for the Unread Alert Notification. @ref BLE_UUID_UNREAD_ALERT_CHAR */
ble_gattc_desc_t unread_alert_cccd; /**< Characteristic Descriptor for Unread Alert Category. Enables or Disables GATT notifications */
} ble_ans_c_service_t;
/**@brief Alert Notification Event structure
*
* @details The structure contains the event that should be handled, as well as
* additional information.
*/
typedef struct
{
ble_ans_c_evt_type_t evt_type; /**< Type of event. */
uint16_t conn_handle; /**< Connection handle on which the ANS service was discovered on the peer device. This will be filled if the evt_type is @ref BLE_ANS_C_EVT_DISCOVERY_COMPLETE.*/
ble_uuid_t uuid; /**< UUID of the event in case of an alert or notification. */
union
{
ble_ans_alert_settings_t settings; /**< Setting returned from server on read request. */
ble_ans_alert_notification_t alert; /**< Alert Notification data sent by the server. */
uint32_t error_code; /**< Additional status/error code if the event was caused by a stack error or gatt status, e.g. during service discovery. */
ble_ans_c_service_t service; /**< Info on the discovered Alert Notification Service discovered. This will be filled if the evt_type is @ref BLE_ANS_C_EVT_DISCOVERY_COMPLETE.*/
} data;
} ble_ans_c_evt_t;
/**@brief Alert Notification event handler type. */
typedef void (*ble_ans_c_evt_handler_t) (ble_ans_c_evt_t * p_evt);
/**@brief Alert Notification structure. This contains various status information for the client. */
struct ble_ans_c_s
{
ble_ans_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Alert Notification Client Application. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
uint8_t central_handle; /**< Handle for the currently connected central if peer is bonded. */
uint8_t service_handle; /**< Handle to the service in the database to use for this instance. */
uint32_t message_buffer_size; /**< Size of message buffer to hold the additional text messages received on notifications. */
uint8_t * p_message_buffer; /**< Pointer to the buffer to be used for additional text message handling. */
ble_ans_c_service_t service; /**< Struct to store the different handles and UUIDs related to the service. */
};
/**@brief Alert Notification init structure. This contains all options and data needed for
* initialization of the client.*/
typedef struct
{
ble_ans_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Battery Service. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
uint32_t message_buffer_size; /**< Size of buffer to handle messages. */
uint8_t * p_message_buffer; /**< Pointer to buffer for passing messages. */
} ble_ans_c_init_t;
/**@brief Function for handling events from the database discovery module.
*
* @details Call this function when getting a callback event from the DB discovery modue.
* This function will handle an event from the database discovery module, and determine
* if it relates to the discovery of heart rate service at the peer. If so, it will
* call the application's event handler indicating that the heart rate 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_ans Pointer to the Alert Notification client structure instance that will handle
* the discovery.
* @param[in] p_evt Pointer to the event received from the database discovery module.
*/
void ble_ans_c_on_db_disc_evt(ble_ans_c_t * p_ans, const ble_db_discovery_evt_t * p_evt);
/**@brief Function for handling the Application's BLE Stack events.
*
* @details Handles all events from the BLE stack of interest to the Alert Notification Client.
*
* @param[in] p_ans Alert Notification Client structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_ans_c_on_ble_evt(ble_ans_c_t * p_ans, const ble_evt_t * p_ble_evt);
/**@brief Function for initializing the Alert Notification Client.
*
* @param[out] p_ans Alert Notification Client structure. This structure will have to be
* supplied by the application. It will be initialized by this function,
* and will later be used to identify this particular client instance.
* @param[in] p_ans_init Information needed to initialize the client.
*
* @return NRF_SUCCESS on successful initialization of client, otherwise an error code.
*/
uint32_t ble_ans_c_init(ble_ans_c_t * p_ans, const ble_ans_c_init_t * p_ans_init);
/**@brief Function for writing the to CCCD to enable new alert notifications from the Alert Notification Service.
*
* @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
* the application. It identifies the particular client instance to use.
*
* @return NRF_SUCCESS on successful writing of the CCCD, otherwise an error code.
*/
uint32_t ble_ans_c_enable_notif_new_alert(const ble_ans_c_t * p_ans);
/**@brief Function for writing to the CCCD to enable unread alert notifications from the Alert Notification Service.
*
* @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
* the application. It identifies the particular client instance to use.
*
* @return NRF_SUCCESS on successful writing of the CCCD, otherwise an error code.
*/
uint32_t ble_ans_c_enable_notif_unread_alert(const ble_ans_c_t * p_ans);
/**@brief Function for writing to the CCCD to disable new alert notifications from the Alert Notification Service.
*
* @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
* the application. It identifies the particular client instance to use.
*
* @return NRF_SUCCESS on successful writing of the CCCD, otherwise an error code.
*/
uint32_t ble_ans_c_disable_notif_new_alert(const ble_ans_c_t * p_ans);
/**@brief Function for writing to the CCCD to disable unread alert notifications from the Alert Notification Service.
*
* @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
* the application. It identifies the particular client instance to use.
*
* @return NRF_SUCCESS on successful writing of the CCCD, otherwise an error code.
*/
uint32_t ble_ans_c_disable_notif_unread_alert(const ble_ans_c_t * p_ans);
/**@brief Function for writing to the Alert Notification Control Point to specify alert notification behavior in the
* Alert Notification Service on the Central.
*
* @param[in] p_ans Alert Notification structure. This structure will have to be
* supplied by the application. It identifies the particular client
* instance to use.
* @param[in] p_control_point Alert Notification Control Point structure. This structure
* specifies the values to write to the Alert Notification Control
* Point, UUID 0x2A44.
*
* @return NRF_SUCCESS on successful writing of the Control Point, otherwise an error code.
*/
uint32_t ble_ans_c_control_point_write(const ble_ans_c_t * p_ans,
const ble_ans_control_point_t * p_control_point);
/**@brief Function for reading the Supported New Alert characteristic value of the service.
* The value describes the alerts supported in the central.
*
* @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
* the application. It identifies the particular client instance to use.
*
* @return NRF_SUCCESS on successful transmission of the read request, otherwise an error code.
*/
uint32_t ble_ans_c_new_alert_read(const ble_ans_c_t * p_ans);
/**@brief Function for reading the Supported Unread Alert characteristic value of the service.
* The value describes the alerts supported in the central.
*
* @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
* the application. It identifies the particular client instance to use.
*
* @return NRF_SUCCESS on successful transmission of the read request, otherwise an error code.
*/
uint32_t ble_ans_c_unread_alert_read(const ble_ans_c_t * p_ans);
/**@brief Function for requesting the peer to notify the New Alert characteristics immediately.
*
* @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
* the application. It identifies the particular client instance to use.
* @param[in] category The category ID for which the peer should notify the client.
*
* @return NRF_SUCCESS on successful transmission of the read request, otherwise an error code.
*/
uint32_t ble_ans_c_new_alert_notify(const ble_ans_c_t * p_ans, ble_ans_category_id_t category);
/**@brief Function for requesting the peer to notify the Unread Alert characteristics immediately.
*
* @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
* the application. It identifies the particular client instance to use.
* @param[in] category The category ID for which the peer should notify the client.
*
* @return NRF_SUCCESS on successful transmission of the read request, otherwise an error code.
*/
uint32_t ble_ans_c_unread_alert_notify(const ble_ans_c_t * p_ans, ble_ans_category_id_t category);
/**@brief Function for assigning a handles to a an instance of ans_c.
*
* @details Call this function when a link has been established with a peer to
* associate this link to an instance of the module. This makes it
* possible to handle several link and associate each link to a particular
* instance of the ans_c module. The connection handle and attribute handles will be
* provided from the discovery event @ref BLE_ANS_C_EVT_DISCOVERY_COMPLETE.
*
* @param[in] p_ans Pointer to the Alert Notification client structure instance to
* associate with the handles.
* @param[in] conn_handle Connection handle to associated with the given Alert Notification Client
* Instance.
* @param[in] p_peer_handles Attribute handles on the ANS server that you want this ANS client to
* interact with.
*
*/
uint32_t ble_ans_c_handles_assign(ble_ans_c_t * p_ans,
const uint16_t conn_handle,
const ble_ans_c_service_t * p_peer_handles);
#endif // BLE_ANS_C_H__
/** @} */

View File

@ -1,316 +0,0 @@
/* 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.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#include "ble_bas.h"
#include <string.h>
#include "nordic_common.h"
#include "ble_srv_common.h"
#include "app_util.h"
#define INVALID_BATTERY_LEVEL 255
/**@brief Function for handling the Connect event.
*
* @param[in] p_bas Battery Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_connect(ble_bas_t * p_bas, ble_evt_t * p_ble_evt)
{
p_bas->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}
/**@brief Function for handling the Disconnect event.
*
* @param[in] p_bas Battery Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_disconnect(ble_bas_t * p_bas, ble_evt_t * p_ble_evt)
{
UNUSED_PARAMETER(p_ble_evt);
p_bas->conn_handle = BLE_CONN_HANDLE_INVALID;
}
/**@brief Function for handling the Write event.
*
* @param[in] p_bas Battery Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_write(ble_bas_t * p_bas, ble_evt_t * p_ble_evt)
{
if (p_bas->is_notification_supported)
{
ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
if (
(p_evt_write->handle == p_bas->battery_level_handles.cccd_handle)
&&
(p_evt_write->len == 2)
)
{
// CCCD written, call application event handler
if (p_bas->evt_handler != NULL)
{
ble_bas_evt_t evt;
if (ble_srv_is_notification_enabled(p_evt_write->data))
{
evt.evt_type = BLE_BAS_EVT_NOTIFICATION_ENABLED;
}
else
{
evt.evt_type = BLE_BAS_EVT_NOTIFICATION_DISABLED;
}
p_bas->evt_handler(p_bas, &evt);
}
}
}
}
void ble_bas_on_ble_evt(ble_bas_t * p_bas, ble_evt_t * p_ble_evt)
{
if (p_bas == NULL || p_ble_evt == NULL)
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_bas, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_bas, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_bas, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
/**@brief Function for adding the Battery Level characteristic.
*
* @param[in] p_bas Battery Service structure.
* @param[in] p_bas_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t battery_level_char_add(ble_bas_t * p_bas, const ble_bas_init_t * p_bas_init)
{
uint32_t err_code;
ble_gatts_char_md_t char_md;
ble_gatts_attr_md_t cccd_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
uint8_t initial_battery_level;
uint8_t encoded_report_ref[BLE_SRV_ENCODED_REPORT_REF_LEN];
uint8_t init_len;
// Add Battery Level characteristic
if (p_bas->is_notification_supported)
{
memset(&cccd_md, 0, sizeof(cccd_md));
// According to BAS_SPEC_V10, the read operation on cccd should be possible without
// authentication.
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
cccd_md.write_perm = p_bas_init->battery_level_char_attr_md.cccd_write_perm;
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
}
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.char_props.notify = (p_bas->is_notification_supported) ? 1 : 0;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = (p_bas->is_notification_supported) ? &cccd_md : NULL;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BATTERY_LEVEL_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
attr_md.read_perm = p_bas_init->battery_level_char_attr_md.read_perm;
attr_md.write_perm = p_bas_init->battery_level_char_attr_md.write_perm;
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 0;
initial_battery_level = p_bas_init->initial_batt_level;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof(uint8_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = sizeof(uint8_t);
attr_char_value.p_value = &initial_battery_level;
err_code = sd_ble_gatts_characteristic_add(p_bas->service_handle, &char_md,
&attr_char_value,
&p_bas->battery_level_handles);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
if (p_bas_init->p_report_ref != NULL)
{
// Add Report Reference descriptor
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_REPORT_REF_DESCR);
memset(&attr_md, 0, sizeof(attr_md));
attr_md.read_perm = p_bas_init->battery_level_report_read_perm;
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 0;
init_len = ble_srv_report_ref_encode(encoded_report_ref, p_bas_init->p_report_ref);
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = init_len;
attr_char_value.init_offs = 0;
attr_char_value.max_len = attr_char_value.init_len;
attr_char_value.p_value = encoded_report_ref;
err_code = sd_ble_gatts_descriptor_add(p_bas->battery_level_handles.value_handle,
&attr_char_value,
&p_bas->report_ref_handle);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
else
{
p_bas->report_ref_handle = BLE_GATT_HANDLE_INVALID;
}
return NRF_SUCCESS;
}
uint32_t ble_bas_init(ble_bas_t * p_bas, const ble_bas_init_t * p_bas_init)
{
if (p_bas == NULL || p_bas_init == NULL)
{
return NRF_ERROR_NULL;
}
uint32_t err_code;
ble_uuid_t ble_uuid;
// Initialize service structure
p_bas->evt_handler = p_bas_init->evt_handler;
p_bas->conn_handle = BLE_CONN_HANDLE_INVALID;
p_bas->is_notification_supported = p_bas_init->support_notification;
p_bas->battery_level_last = INVALID_BATTERY_LEVEL;
// Add service
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BATTERY_SERVICE);
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_bas->service_handle);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add battery level characteristic
return battery_level_char_add(p_bas, p_bas_init);
}
uint32_t ble_bas_battery_level_update(ble_bas_t * p_bas, uint8_t battery_level)
{
if (p_bas == NULL)
{
return NRF_ERROR_NULL;
}
uint32_t err_code = NRF_SUCCESS;
ble_gatts_value_t gatts_value;
if (battery_level != p_bas->battery_level_last)
{
// Initialize value struct.
memset(&gatts_value, 0, sizeof(gatts_value));
gatts_value.len = sizeof(uint8_t);
gatts_value.offset = 0;
gatts_value.p_value = &battery_level;
// Update database.
err_code = sd_ble_gatts_value_set(p_bas->conn_handle,
p_bas->battery_level_handles.value_handle,
&gatts_value);
if (err_code == NRF_SUCCESS)
{
// Save new battery value.
p_bas->battery_level_last = battery_level;
}
else
{
return err_code;
}
// Send value if connected and notifying.
if ((p_bas->conn_handle != BLE_CONN_HANDLE_INVALID) && p_bas->is_notification_supported)
{
ble_gatts_hvx_params_t hvx_params;
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_bas->battery_level_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
hvx_params.offset = gatts_value.offset;
hvx_params.p_len = &gatts_value.len;
hvx_params.p_data = gatts_value.p_value;
err_code = sd_ble_gatts_hvx(p_bas->conn_handle, &hvx_params);
}
else
{
err_code = NRF_ERROR_INVALID_STATE;
}
}
return err_code;
}

View File

@ -1,133 +0,0 @@
/* 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_bas Battery Service
* @{
* @ingroup ble_sdk_srv
* @brief Battery Service module.
*
* @details This module implements the Battery Service with the Battery Level characteristic.
* During initialization it adds the Battery Service and Battery Level characteristic
* to the BLE stack database. Optionally it can also add a Report Reference descriptor
* to the Battery Level characteristic (used when including the Battery Service in
* the HID service).
*
* If specified, the module will support notification of the Battery Level characteristic
* through the ble_bas_battery_level_update() function.
* If an event handler is supplied by the application, the Battery Service will
* generate Battery Service events to the application.
*
* @note The application must propagate BLE stack events to the Battery Service module by calling
* ble_bas_on_ble_evt() from the @ref softdevice_handler callback.
*
* @note Attention!
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_BAS_H__
#define BLE_BAS_H__
#include <stdint.h>
#include <stdbool.h>
#include "ble.h"
#include "ble_srv_common.h"
/**@brief Battery Service event type. */
typedef enum
{
BLE_BAS_EVT_NOTIFICATION_ENABLED, /**< Battery value notification enabled event. */
BLE_BAS_EVT_NOTIFICATION_DISABLED /**< Battery value notification disabled event. */
} ble_bas_evt_type_t;
/**@brief Battery Service event. */
typedef struct
{
ble_bas_evt_type_t evt_type; /**< Type of event. */
} ble_bas_evt_t;
// Forward declaration of the ble_bas_t type.
typedef struct ble_bas_s ble_bas_t;
/**@brief Battery Service event handler type. */
typedef void (*ble_bas_evt_handler_t) (ble_bas_t * p_bas, ble_bas_evt_t * p_evt);
/**@brief Battery Service init structure. This contains all options and data needed for
* initialization of the service.*/
typedef struct
{
ble_bas_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Battery Service. */
bool support_notification; /**< TRUE if notification of Battery Level measurement is supported. */
ble_srv_report_ref_t * p_report_ref; /**< If not NULL, a Report Reference descriptor with the specified value will be added to the Battery Level characteristic */
uint8_t initial_batt_level; /**< Initial battery level */
ble_srv_cccd_security_mode_t battery_level_char_attr_md; /**< Initial security level for battery characteristics attribute */
ble_gap_conn_sec_mode_t battery_level_report_read_perm; /**< Initial security level for battery report read attribute */
} ble_bas_init_t;
/**@brief Battery Service structure. This contains various status information for the service. */
struct ble_bas_s
{
ble_bas_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Battery Service. */
uint16_t service_handle; /**< Handle of Battery Service (as provided by the BLE stack). */
ble_gatts_char_handles_t battery_level_handles; /**< Handles related to the Battery Level characteristic. */
uint16_t report_ref_handle; /**< Handle of the Report Reference descriptor. */
uint8_t battery_level_last; /**< Last Battery Level measurement passed to the Battery Service. */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
bool is_notification_supported; /**< TRUE if notification of Battery Level is supported. */
};
/**@brief Function for initializing the Battery Service.
*
* @param[out] p_bas Battery Service structure. This structure will have to be supplied by
* the application. It will be initialized by this function, and will later
* be used to identify this particular service instance.
* @param[in] p_bas_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
*/
uint32_t ble_bas_init(ble_bas_t * p_bas, const ble_bas_init_t * p_bas_init);
/**@brief Function for handling the Application's BLE Stack events.
*
* @details Handles all events from the BLE stack of interest to the Battery Service.
*
* @note For the requirements in the BAS specification to be fulfilled,
* ble_bas_battery_level_update() must be called upon reconnection if the
* battery level has changed while the service has been disconnected from a bonded
* client.
*
* @param[in] p_bas Battery Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_bas_on_ble_evt(ble_bas_t * p_bas, ble_evt_t * p_ble_evt);
/**@brief Function for updating the battery level.
*
* @details The application calls this function after having performed a battery measurement. If
* notification has been enabled, the battery level characteristic is sent to the client.
*
* @note For the requirements in the BAS specification to be fulfilled,
* this function must be called upon reconnection if the battery level has changed
* while the service has been disconnected from a bonded client.
*
* @param[in] p_bas Battery Service structure.
* @param[in] battery_level New battery measurement value (in percent of full capacity).
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
uint32_t ble_bas_battery_level_update(ble_bas_t * p_bas, uint8_t battery_level);
#endif // BLE_BAS_H__
/** @} */

View File

@ -1,370 +0,0 @@
/*
* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is confidential property of Nordic Semiconductor. The use,
* copying, transfer or disclosure of such information is prohibited except by express written
* agreement with Nordic Semiconductor.
*
*/
#include "ble_bas_c.h"
#include "ble_db_discovery.h"
#include "ble_types.h"
#include "ble_srv_common.h"
#include "ble_gattc.h"
#include "app_trace.h"
#include "sdk_common.h"
#define LOG app_trace_log /**< Debug logger macro that will be used in this file to do logging of important information over UART. */
#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 the send buffer, which is 1 higher than the mask. */
#define WRITE_MESSAGE_LENGTH BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
typedef enum
{
READ_REQ, /**< Type identifying that this tx_message is a read request. */
WRITE_REQ /**< Type identifying that this tx_message is a write request. */
} tx_request_t;
/**@brief Structure for writing a message to the peer, i.e. CCCD.
*/
typedef struct
{
uint8_t gattc_value[WRITE_MESSAGE_LENGTH]; /**< The message to write. */
ble_gattc_write_params_t gattc_params; /**< The GATTC parameters for this message. */
} write_params_t;
/**@brief Structure for holding the data that will be transmitted to the connected central.
*/
typedef struct
{
uint16_t conn_handle; /**< Connection handle to be used when transmitting this message. */
tx_request_t type; /**< Type of message. (read or write). */
union
{
uint16_t read_handle; /**< Read request handle. */
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 the messages that will be transmitted to the central. */
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 containing the next message to be transmitted. */
/**@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)
{
LOG("[BAS_C]: SD Read/Write API returns Success..\r\n");
m_tx_index++;
m_tx_index &= TX_BUFFER_MASK;
}
else
{
LOG("[BAS_C]: SD Read/Write API returns error. This message sending will be "
"attempted again..\r\n");
}
}
}
/**@brief Function for handling write response events.
*
* @param[in] p_bas_c Pointer to the Battery Service Client Structure.
* @param[in] p_ble_evt Pointer to the SoftDevice event.
*/
static void on_write_rsp(ble_bas_c_t * p_bas_c, const ble_evt_t * p_ble_evt)
{
// Check if the event if on the link for this instance
if (p_bas_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
{
return;
}
// Check if there is any message to be sent across to the peer and send it.
tx_buffer_process();
}
/**@brief Function for handling read response events.
*
* @details This function will validate the read response and raise the appropriate
* event to the application.
*
* @param[in] p_bas_c Pointer to the Battery Service Client Structure.
* @param[in] p_ble_evt Pointer to the SoftDevice event.
*/
static void on_read_rsp(ble_bas_c_t * p_bas_c, const ble_evt_t * p_ble_evt)
{
const ble_gattc_evt_read_rsp_t * p_response;
// Check if the event if on the link for this instance
if (p_bas_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
{
return;
}
p_response = &p_ble_evt->evt.gattc_evt.params.read_rsp;
if (p_response->handle == p_bas_c->peer_bas_db.bl_handle)
{
ble_bas_c_evt_t evt;
evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
evt.evt_type = BLE_BAS_C_EVT_BATT_READ_RESP;
evt.params.battery_level = p_response->data[0];
p_bas_c->evt_handler(p_bas_c, &evt);
}
// Check if there is any buffered transmissions and send them.
tx_buffer_process();
}
/**@brief Function for handling Handle Value Notification received from the SoftDevice.
*
* @details This function will handle the Handle Value Notification received from the SoftDevice
* and checks if it is a notification of the Battery Level measurement from the peer. If
* so, this function will decode the battery level measurement and send it to the
* application.
*
* @param[in] p_ble_bas_c Pointer to the Battery Service Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_hvx(ble_bas_c_t * p_ble_bas_c, const ble_evt_t * p_ble_evt)
{
// Check if the event if on the link for this instance
if (p_ble_bas_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
{
return;
}
// Check if this notification is a battery level notification.
if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_bas_c->peer_bas_db.bl_handle)
{
if (p_ble_evt->evt.gattc_evt.params.hvx.len == 1)
{
ble_bas_c_evt_t ble_bas_c_evt;
ble_bas_c_evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
ble_bas_c_evt.evt_type = BLE_BAS_C_EVT_BATT_NOTIFICATION;
ble_bas_c_evt.params.battery_level = p_ble_evt->evt.gattc_evt.params.hvx.data[0];
p_ble_bas_c->evt_handler(p_ble_bas_c, &ble_bas_c_evt);
}
}
}
void ble_bas_on_db_disc_evt(ble_bas_c_t * p_ble_bas_c, const ble_db_discovery_evt_t * p_evt)
{
// Check if the Battery Service was discovered.
if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE
&&
p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_BATTERY_SERVICE
&&
p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
{
// Find the CCCD Handle of the Battery Level characteristic.
uint8_t i;
ble_bas_c_evt_t evt;
evt.evt_type = BLE_BAS_C_EVT_DISCOVERY_COMPLETE;
evt.conn_handle = p_evt->conn_handle;
for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid ==
BLE_UUID_BATTERY_LEVEL_CHAR)
{
// Found Battery Level characteristic. Store CCCD handle and break.
evt.params.bas_db.bl_cccd_handle =
p_evt->params.discovered_db.charateristics[i].cccd_handle;
evt.params.bas_db.bl_handle =
p_evt->params.discovered_db.charateristics[i].characteristic.handle_value;
break;
}
}
LOG("[BAS_C]: Battery Service discovered at peer.\r\n");
//If the instance has been assigned prior to db_discovery, assign the db_handles
if(p_ble_bas_c->conn_handle != BLE_CONN_HANDLE_INVALID)
{
if ((p_ble_bas_c->peer_bas_db.bl_cccd_handle == BLE_GATT_HANDLE_INVALID)&&
(p_ble_bas_c->peer_bas_db.bl_handle == BLE_GATT_HANDLE_INVALID))
{
p_ble_bas_c->peer_bas_db = evt.params.bas_db;
}
}
p_ble_bas_c->evt_handler(p_ble_bas_c, &evt);
}
else
{
LOG("[BAS_C]: Battery Service discovery failure at peer. \r\n");
}
}
/**@brief Function for creating a message for writing to the CCCD.
*/
static uint32_t cccd_configure(uint16_t conn_handle, uint16_t handle_cccd, bool notification_enable)
{
LOG("[BAS_C]: Configuring CCCD. CCCD Handle = %d, Connection Handle = %d\r\n",
handle_cccd,conn_handle);
tx_message_t * p_msg;
uint16_t cccd_val = notification_enable ? BLE_GATT_HVX_NOTIFICATION : 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 = 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_16(cccd_val);
p_msg->req.write_req.gattc_value[1] = MSB_16(cccd_val);
p_msg->conn_handle = conn_handle;
p_msg->type = WRITE_REQ;
tx_buffer_process();
return NRF_SUCCESS;
}
uint32_t ble_bas_c_init(ble_bas_c_t * p_ble_bas_c, ble_bas_c_init_t * p_ble_bas_c_init)
{
VERIFY_PARAM_NOT_NULL(p_ble_bas_c);
VERIFY_PARAM_NOT_NULL(p_ble_bas_c_init);
ble_uuid_t bas_uuid;
bas_uuid.type = BLE_UUID_TYPE_BLE;
bas_uuid.uuid = BLE_UUID_BATTERY_SERVICE;
p_ble_bas_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ble_bas_c->peer_bas_db.bl_cccd_handle = BLE_GATT_HANDLE_INVALID;
p_ble_bas_c->peer_bas_db.bl_handle = BLE_GATT_HANDLE_INVALID;
p_ble_bas_c->evt_handler = p_ble_bas_c_init->evt_handler;
return ble_db_discovery_evt_register(&bas_uuid);
}
/**@brief Function for handling Disconnected event received from the SoftDevice.
*
* @details This function check if the disconnect event is happening on the link
* associated with the current instance of the module, if so it will set its
* conn_handle to invalid.
*
* @param[in] p_ble_bas_c Pointer to the Battery Service Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_disconnected(ble_bas_c_t * p_ble_bas_c, const ble_evt_t * p_ble_evt)
{
if (p_ble_bas_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
{
p_ble_bas_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ble_bas_c->peer_bas_db.bl_cccd_handle = BLE_GATT_HANDLE_INVALID;
p_ble_bas_c->peer_bas_db.bl_handle = BLE_GATT_HANDLE_INVALID;
}
}
void ble_bas_c_on_ble_evt(ble_bas_c_t * p_ble_bas_c, const ble_evt_t * p_ble_evt)
{
if ((p_ble_bas_c == NULL) || (p_ble_evt == NULL))
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_GATTC_EVT_HVX:
on_hvx(p_ble_bas_c, p_ble_evt);
break;
case BLE_GATTC_EVT_WRITE_RSP:
on_write_rsp(p_ble_bas_c, p_ble_evt);
break;
case BLE_GATTC_EVT_READ_RSP:
on_read_rsp(p_ble_bas_c, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnected(p_ble_bas_c, p_ble_evt);
break;
default:
break;
}
}
uint32_t ble_bas_c_bl_notif_enable(ble_bas_c_t * p_ble_bas_c)
{
VERIFY_PARAM_NOT_NULL(p_ble_bas_c);
if (p_ble_bas_c->conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
return cccd_configure(p_ble_bas_c->conn_handle, p_ble_bas_c->peer_bas_db.bl_cccd_handle, true);
}
uint32_t ble_bas_c_bl_read(ble_bas_c_t * p_ble_bas_c)
{
VERIFY_PARAM_NOT_NULL(p_ble_bas_c);
if (p_ble_bas_c->conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
tx_message_t * msg;
msg = &m_tx_buffer[m_tx_insert_index++];
m_tx_insert_index &= TX_BUFFER_MASK;
msg->req.read_handle = p_ble_bas_c->peer_bas_db.bl_handle;
msg->conn_handle = p_ble_bas_c->conn_handle;
msg->type = READ_REQ;
tx_buffer_process();
return NRF_SUCCESS;
}
uint32_t ble_bas_c_handles_assign(ble_bas_c_t * p_ble_bas_c,
uint16_t conn_handle,
ble_bas_c_db_t * p_peer_handles)
{
VERIFY_PARAM_NOT_NULL(p_ble_bas_c);
p_ble_bas_c->conn_handle = conn_handle;
if (p_peer_handles != NULL)
{
p_ble_bas_c->peer_bas_db = *p_peer_handles;
}
return NRF_SUCCESS;
}

View File

@ -1,212 +0,0 @@
/*
* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is confidential property of Nordic Semiconductor. The use,
* copying, transfer or disclosure of such information is prohibited except by express written
* agreement with Nordic Semiconductor.
*
*/
/**@file
*
* @defgroup ble_sdk_srv_bas_c Battery Service Client
* @{
* @ingroup ble_sdk_srv
* @brief Battery Service Client module.
*
* @details This module contains APIs to read and interact with the Battery Service of a remote
* device.
*
* @note The application must propagate BLE stack events to this module by calling
* ble_hrs_c_on_ble_evt().
*
*/
#ifndef BLE_BAS_C_H__
#define BLE_BAS_C_H__
#include <stdint.h>
#include "ble.h"
#include "ble_db_discovery.h"
/**
* @defgroup bas_c_enums Enumerations
* @{
*/
/**@brief Battery Service Client event type. */
typedef enum
{
BLE_BAS_C_EVT_DISCOVERY_COMPLETE, /**< Event indicating that the Battery Service has been discovered at the peer. */
BLE_BAS_C_EVT_BATT_NOTIFICATION, /**< Event indicating that a notification of the Battery Level characteristic has been received from the peer. */
BLE_BAS_C_EVT_BATT_READ_RESP /**< Event indicating that a read response on Battery Level characteristic has been received from peer. */
} ble_bas_c_evt_type_t;
/** @} */
/**
* @defgroup bas_c_structs Structures
* @{
*/
/**@brief Structure containing the handles related to the Battery Service found on the peer. */
typedef struct
{
uint16_t bl_cccd_handle; /**< Handle of the CCCD of the Battery Level characteristic. */
uint16_t bl_handle; /**< Handle of the Battery Level characteristic as provided by the SoftDevice. */
} ble_bas_c_db_t;
/**@brief Battery Service Client Event structure. */
typedef struct
{
ble_bas_c_evt_type_t evt_type; /**< Event Type. */
uint16_t conn_handle; /**< Connection handle relevent to this event.*/
union
{
ble_bas_c_db_t bas_db; /**< Battery Service related handles found on the peer device. This will be filled if the evt_type is @ref BLE_BAS_C_EVT_DISCOVERY_COMPLETE.*/
uint8_t battery_level; /**< Battery level received from peer. This field will be used for the events @ref BLE_BAS_C_EVT_BATT_NOTIFICATION and @ref BLE_BAS_C_EVT_BATT_READ_RESP.*/
} params;
} ble_bas_c_evt_t;
/** @} */
/**
* @defgroup bas_c_types Types
* @{
*/
// Forward declaration of the ble_bas_t type.
typedef struct ble_bas_c_s ble_bas_c_t;
/**@brief Event handler type.
*
* @details This is the type of the event handler that should be provided by the application
* of this module in order to receive events.
*/
typedef void (* ble_bas_c_evt_handler_t) (ble_bas_c_t * p_bas_bas_c, ble_bas_c_evt_t * p_evt);
/** @} */
/**
* @addtogroup bas_c_structs
* @{
*/
/**@brief Battery Service Client structure.
*/
struct ble_bas_c_s
{
uint16_t conn_handle; /**< Connection handle as provided by the SoftDevice. */
ble_bas_c_db_t peer_bas_db; /**< Handles related to BAS on the peer*/
ble_bas_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the Battery service. */
};
/**@brief Battery Service Client initialization structure.
*/
typedef struct
{
ble_bas_c_evt_handler_t evt_handler; /**< Event handler to be called by the Battery Service Client module whenever there is an event related to the Battery Service. */
} ble_bas_c_init_t;
/** @} */
/**
* @defgroup bas_c_functions Functions
* @{
*/
/**@brief Function for initializing the Battery Service Client module.
*
* @details This function will initialize the module and set up Database Discovery to discover
* the Battery Service. After calling this function, call @ref ble_db_discovery_start
* to start discovery once a link with a peer has been established.
*
* @param[out] p_ble_bas_c Pointer to the Battery Service client structure.
* @param[in] p_ble_bas_c_init Pointer to the Battery Service initialization structure containing
* the initialization information.
*
* @retval NRF_SUCCESS Operation success.
* @retval NRF_ERROR_NULL A parameter is NULL.
* Otherwise, an error code returned by @ref ble_db_discovery_evt_register.
*/
uint32_t ble_bas_c_init(ble_bas_c_t * p_ble_bas_c, ble_bas_c_init_t * p_ble_bas_c_init);
/**@brief Function for handling BLE events from the SoftDevice.
*
* @details This function will handle the BLE events received from the SoftDevice. If the BLE
* event is relevant for the Battery Service Client module, then it is used to update
* interval variables and, if necessary, send events to the application.
*
* @note This function must be called by the application.
*
* @param[in] p_ble_bas_c Pointer to the Battery Service client structure.
* @param[in] p_ble_evt Pointer to the BLE event.
*/
void ble_bas_c_on_ble_evt(ble_bas_c_t * p_ble_bas_c, const ble_evt_t * p_ble_evt);
/**@brief Function for enabling notifications on the Battery Level characteristic.
*
* @details This function will enable to notification of the Battery Level characteristic at the
* peer by writing to the CCCD of the Battery Level Characteristic.
*
* @param p_ble_bas_c Pointer to the Battery Service client structure.
*
* @retval NRF_SUCCESS If the SoftDevice has been requested to write to the CCCD of the peer.
* NRF_ERROR_NULL Parameter is NULL.
* Otherwise, an error code returned by the SoftDevice API @ref
* sd_ble_gattc_write.
*/
uint32_t ble_bas_c_bl_notif_enable(ble_bas_c_t * p_ble_bas_c);
/**@brief Function for reading the Battery Level characteristic.
*
* @param p_ble_bas_c Pointer to the Battery Service client structure.
*
* @retval NRF_SUCCESS If the read request was successfully queued to be sent to peer.
*/
uint32_t ble_bas_c_bl_read(ble_bas_c_t * p_ble_bas_c);
/**@brief Function for handling events from the database discovery module.
*
* @details Call this function when getting a callback event from the DB discovery modue.
* This function will handle an event from the database discovery module, and determine
* if it relates to the discovery of Battery service at the peer. If so, it will
* call the application's event handler indicating that the Battery service has been
* discovered at the peer. It also populates the event with the service related
* information before providing it to the application.
*
* @param p_ble_bas_c Pointer to the Battery Service client structure.
* @param[in] p_evt Pointer to the event received from the database discovery module.
*
*/
void ble_bas_on_db_disc_evt(ble_bas_c_t * p_ble_bas_c, const ble_db_discovery_evt_t * p_evt);
/**@brief Function for assigning handles to a this instance of bas_c.
*
* @details Call this function when a link has been established with a peer to
* associate this link to this instance of the module. This makes it
* possible to handle several link and associate each link to a particular
* instance of this module. The connection handle and attribute handles will be
* provided from the discovery event @ref BLE_BAS_C_EVT_DISCOVERY_COMPLETE.
*
* @param[in] p_ble_bas_c Pointer to the Battery client structure instance to associate.
* @param[in] conn_handle Connection handle to associated with the given Battery Client Instance.
* @param[in] p_peer_handles Attribute handles on the BAS server you want this BAS client to
* interact with.
*/
uint32_t ble_bas_c_handles_assign(ble_bas_c_t * p_ble_bas_c,
uint16_t conn_handle,
ble_bas_c_db_t * p_peer_handles);
/** @} */ // End tag for Function group.
#endif // BLE_BAS_C_H__
/** @} */ // End tag for the file.

View File

@ -1,439 +0,0 @@
/* 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.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#include "ble_bps.h"
#include <string.h>
#include "nordic_common.h"
#include "ble_l2cap.h"
#include "ble_srv_common.h"
#include "app_util.h"
#define OPCODE_LENGTH 1 /**< Length of opcode inside Blood Pressure Measurement packet. */
#define HANDLE_LENGTH 2 /**< Length of handle inside Blood Pressure Measurement packet. */
#define MAX_BPM_LEN (BLE_L2CAP_MTU_DEF - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Blood Pressure Measurement. */
// Blood Pressure Measurement Flags bits
#define BPS_MEAS_BLOOD_PRESSURE_UNITS_FLAG_BIT (0x01 << 0) /**< Blood Pressure Units Flag bit. */
#define BPS_MEAS_TIME_STAMP_FLAG_BIT (0x01 << 1) /**< Time Stamp Flag bit. */
#define BPS_MEAS_PULSE_RATE_FLAG_BIT (0x01 << 2) /**< Pulse Rate Flag bit. */
#define BPS_MEAS_USER_ID_FLAG_BIT (0x01 << 3) /**< User ID Flag bit. */
#define BPS_MEAS_MEASUREMENT_STATUS_FLAG_BIT (0x01 << 4) /**< Measurement Status Flag bit. */
/**@brief Function for handling the Connect event.
*
* @param[in] p_bps Blood Pressure Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_connect(ble_bps_t * p_bps, ble_evt_t * p_ble_evt)
{
p_bps->conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
}
/**@brief Function for handling the Disconnect event.
*
* @param[in] p_bps Blood Pressure Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_disconnect(ble_bps_t * p_bps, ble_evt_t * p_ble_evt)
{
UNUSED_PARAMETER(p_ble_evt);
p_bps->conn_handle = BLE_CONN_HANDLE_INVALID;
}
/**@brief Function for handling the write events to the Blood Pressure Measurement characteristic.
*
* @param[in] p_bps Blood Pressure Service structure.
* @param[in] p_evt_write Write event received from the BLE stack.
*/
static void on_cccd_write(ble_bps_t * p_bps, ble_gatts_evt_write_t * p_evt_write)
{
if (p_evt_write->len == 2)
{
// CCCD written, update indication state
if (p_bps->evt_handler != NULL)
{
ble_bps_evt_t evt;
if (ble_srv_is_indication_enabled(p_evt_write->data))
{
evt.evt_type = BLE_BPS_EVT_INDICATION_ENABLED;
}
else
{
evt.evt_type = BLE_BPS_EVT_INDICATION_DISABLED;
}
p_bps->evt_handler(p_bps, &evt);
}
}
}
/**@brief Function for handling the Write event.
*
* @param[in] p_bps Blood Pressure Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_write(ble_bps_t * p_bps, ble_evt_t * p_ble_evt)
{
ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
if (p_evt_write->handle == p_bps->meas_handles.cccd_handle)
{
on_cccd_write(p_bps, p_evt_write);
}
}
/**@brief Function for handling the HVC event.
*
* @details Handles HVC events from the BLE stack.
*
* @param[in] p_bps Blood Pressure Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_hvc(ble_bps_t * p_bps, ble_evt_t * p_ble_evt)
{
ble_gatts_evt_hvc_t * p_hvc = &p_ble_evt->evt.gatts_evt.params.hvc;
if (p_hvc->handle == p_bps->meas_handles.value_handle)
{
ble_bps_evt_t evt;
evt.evt_type = BLE_BPS_EVT_INDICATION_CONFIRMED;
p_bps->evt_handler(p_bps, &evt);
}
}
void ble_bps_on_ble_evt(ble_bps_t * p_bps, ble_evt_t * p_ble_evt)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_bps, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_bps, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_bps, p_ble_evt);
break;
case BLE_GATTS_EVT_HVC:
on_hvc(p_bps, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
/**@brief Function for encoding a Blood Pressure Measurement.
*
* @param[in] p_bps Blood Pressure Service structure.
* @param[in] p_bps_meas Measurement to be encoded.
* @param[out] p_encoded_buffer Buffer where the encoded data will be written.
*
* @return Size of encoded data.
*/
static uint8_t bps_measurement_encode(ble_bps_t * p_bps,
ble_bps_meas_t * p_bps_meas,
uint8_t * p_encoded_buffer)
{
uint8_t flags = 0;
uint8_t len = 1;
uint16_t encoded_sfloat;
// Set measurement units flag
if (p_bps_meas->blood_pressure_units_in_kpa)
{
flags |= BPS_MEAS_BLOOD_PRESSURE_UNITS_FLAG_BIT;
}
// Blood Pressure Measurement - Systolic
encoded_sfloat = ((p_bps_meas->blood_pressure_systolic.exponent << 12) & 0xF000) |
((p_bps_meas->blood_pressure_systolic.mantissa << 0) & 0x0FFF);
len += uint16_encode(encoded_sfloat, &p_encoded_buffer[len]);
// Blood Pressure Measurement - Diastolic
encoded_sfloat = ((p_bps_meas->blood_pressure_diastolic.exponent << 12) & 0xF000) |
((p_bps_meas->blood_pressure_diastolic.mantissa << 0) & 0x0FFF);
len += uint16_encode(encoded_sfloat, &p_encoded_buffer[len]);
// Blood Pressure Measurement - Mean Arterial Pressure
encoded_sfloat = ((p_bps_meas->mean_arterial_pressure.exponent << 12) & 0xF000) |
((p_bps_meas->mean_arterial_pressure.mantissa << 0) & 0x0FFF);
len += uint16_encode(encoded_sfloat, &p_encoded_buffer[len]);
// Time Stamp field
if (p_bps_meas->time_stamp_present)
{
flags |= BPS_MEAS_TIME_STAMP_FLAG_BIT;
len += ble_date_time_encode(&p_bps_meas->time_stamp, &p_encoded_buffer[len]);
}
// Pulse Rate
if (p_bps_meas->pulse_rate_present)
{
flags |= BPS_MEAS_PULSE_RATE_FLAG_BIT;
encoded_sfloat = ((p_bps_meas->pulse_rate.exponent << 12) & 0xF000) |
((p_bps_meas->pulse_rate.mantissa << 0) & 0x0FFF);
len += uint16_encode(encoded_sfloat, &p_encoded_buffer[len]);
}
// User ID
if (p_bps_meas->user_id_present)
{
flags |= BPS_MEAS_USER_ID_FLAG_BIT;
p_encoded_buffer[len++] = p_bps_meas->user_id;
}
// Measurement Status
if (p_bps_meas->measurement_status_present)
{
flags |= BPS_MEAS_MEASUREMENT_STATUS_FLAG_BIT;
len += uint16_encode(p_bps_meas->measurement_status, &p_encoded_buffer[len]);
}
// Flags field
p_encoded_buffer[0] = flags;
return len;
}
/**@brief Function for adding Blood Pressure Measurement characteristics.
*
* @param[in] p_bps Blood Pressure Service structure.
* @param[in] p_bps_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t bps_measurement_char_add(ble_bps_t * p_bps, const ble_bps_init_t * p_bps_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_md_t cccd_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
ble_bps_meas_t initial_bpm;
uint8_t encoded_bpm[MAX_BPM_LEN];
memset(&cccd_md, 0, sizeof(cccd_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
cccd_md.write_perm = p_bps_init->bps_meas_attr_md.cccd_write_perm;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.indicate = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = &cccd_md;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BLOOD_PRESSURE_MEASUREMENT_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.read_perm = p_bps_init->bps_meas_attr_md.read_perm;
attr_md.write_perm = p_bps_init->bps_meas_attr_md.write_perm;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
memset(&initial_bpm, 0, sizeof(initial_bpm));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = bps_measurement_encode(p_bps, &initial_bpm, encoded_bpm);
attr_char_value.init_offs = 0;
attr_char_value.max_len = MAX_BPM_LEN;
attr_char_value.p_value = encoded_bpm;
return sd_ble_gatts_characteristic_add(p_bps->service_handle,
&char_md,
&attr_char_value,
&p_bps->meas_handles);
}
/**@brief Function for adding Blood Pressure Feature characteristics.
*
* @param[in] p_bps Blood Pressure Service structure.
* @param[in] p_bps_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t bps_feature_char_add(ble_bps_t * p_bps, const ble_bps_init_t * p_bps_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
uint8_t init_value_encoded[2];
uint8_t init_value_len;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BLOOD_PRESSURE_FEATURE_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.read_perm = p_bps_init->bps_feature_attr_md.read_perm;
attr_md.write_perm = p_bps_init->bps_feature_attr_md.write_perm;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 0;
memset(&attr_char_value, 0, sizeof(attr_char_value));
init_value_len = uint16_encode(p_bps_init->feature, init_value_encoded);
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = init_value_len;
attr_char_value.init_offs = 0;
attr_char_value.max_len = init_value_len;
attr_char_value.p_value = init_value_encoded;
return sd_ble_gatts_characteristic_add(p_bps->service_handle,
&char_md,
&attr_char_value,
&p_bps->feature_handles);
}
uint32_t ble_bps_init(ble_bps_t * p_bps, const ble_bps_init_t * p_bps_init)
{
uint32_t err_code;
ble_uuid_t ble_uuid;
// Initialize service structure
p_bps->evt_handler = p_bps_init->evt_handler;
p_bps->conn_handle = BLE_CONN_HANDLE_INVALID;
p_bps->feature = p_bps_init->feature;
// Add service
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BLOOD_PRESSURE_SERVICE);
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_bps->service_handle);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add measurement characteristic
err_code = bps_measurement_char_add(p_bps, p_bps_init);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add feature characteristic
err_code = bps_feature_char_add(p_bps, p_bps_init);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
return NRF_SUCCESS;
}
uint32_t ble_bps_measurement_send(ble_bps_t * p_bps, ble_bps_meas_t * p_bps_meas)
{
uint32_t err_code;
// Send value if connected
if (p_bps->conn_handle != BLE_CONN_HANDLE_INVALID)
{
uint8_t encoded_bps_meas[MAX_BPM_LEN];
uint16_t len;
uint16_t hvx_len;
ble_gatts_hvx_params_t hvx_params;
len = bps_measurement_encode(p_bps, p_bps_meas, encoded_bps_meas);
hvx_len = len;
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_bps->meas_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_INDICATION;
hvx_params.offset = 0;
hvx_params.p_len = &hvx_len;
hvx_params.p_data = encoded_bps_meas;
err_code = sd_ble_gatts_hvx(p_bps->conn_handle, &hvx_params);
if ((err_code == NRF_SUCCESS) && (hvx_len != len))
{
err_code = NRF_ERROR_DATA_SIZE;
}
}
else
{
err_code = NRF_ERROR_INVALID_STATE;
}
return err_code;
}
uint32_t ble_bps_is_indication_enabled(ble_bps_t * p_bps, bool * p_indication_enabled)
{
uint32_t err_code;
uint8_t cccd_value_buf[BLE_CCCD_VALUE_LEN];
ble_gatts_value_t gatts_value;
// Initialize value struct.
memset(&gatts_value, 0, sizeof(gatts_value));
gatts_value.len = BLE_CCCD_VALUE_LEN;
gatts_value.offset = 0;
gatts_value.p_value = cccd_value_buf;
err_code = sd_ble_gatts_value_get(p_bps->conn_handle,
p_bps->meas_handles.cccd_handle,
&gatts_value);
if (err_code == NRF_SUCCESS)
{
*p_indication_enabled = ble_srv_is_indication_enabled(cccd_value_buf);
}
return err_code;
}

View File

@ -1,161 +0,0 @@
/* 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.
*/
/** @file
*
* @defgroup ble_sdk_srv_bps Blood Pressure Service
* @{
* @ingroup ble_sdk_srv
* @brief Blood Pressure Service module.
*
* @details This module implements the Blood Pressure Service.
*
* If an event handler is supplied by the application, the Blood Pressure
* Service will generate Blood Pressure Service events to the application.
*
* @note The application must propagate BLE stack events to the Blood Pressure Service
* module by calling ble_bps_on_ble_evt() from the @ref softdevice_handler function.
*
* @note Attention!
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_BPS_H__
#define BLE_BPS_H__
#include <stdint.h>
#include <stdbool.h>
#include "ble.h"
#include "ble_srv_common.h"
#include "ble_date_time.h"
// Blood Pressure Feature bits
#define BLE_BPS_FEATURE_BODY_MOVEMENT_BIT (0x01 << 0) /**< Body Movement Detection Support bit. */
#define BLE_BPS_FEATURE_CUFF_FIT_BIT (0x01 << 1) /**< Cuff Fit Detection Support bit. */
#define BLE_BPS_FEATURE_IRREGULAR_PULSE_BIT (0x01 << 2) /**< Irregular Pulse Detection Support bit. */
#define BLE_BPS_FEATURE_PULSE_RATE_RANGE_BIT (0x01 << 3) /**< Pulse Rate Range Detection Support bit. */
#define BLE_BPS_FEATURE_MEASUREMENT_POSITION_BIT (0x01 << 4) /**< Measurement Position Detection Support bit. */
#define BLE_BPS_FEATURE_MULTIPLE_BOND_BIT (0x01 << 5) /**< Multiple Bond Support bit. */
/**@brief Blood Pressure Service event type. */
typedef enum
{
BLE_BPS_EVT_INDICATION_ENABLED, /**< Blood Pressure value indication enabled event. */
BLE_BPS_EVT_INDICATION_DISABLED, /**< Blood Pressure value indication disabled event. */
BLE_BPS_EVT_INDICATION_CONFIRMED /**< Confirmation of a blood pressure measurement indication has been received. */
} ble_bps_evt_type_t;
/**@brief Blood Pressure Service event. */
typedef struct
{
ble_bps_evt_type_t evt_type; /**< Type of event. */
} ble_bps_evt_t;
// Forward declaration of the ble_bps_t type.
typedef struct ble_bps_s ble_bps_t;
/**@brief Blood Pressure Service event handler type. */
typedef void (*ble_bps_evt_handler_t) (ble_bps_t * p_bps, ble_bps_evt_t * p_evt);
/**@brief SFLOAT format (IEEE-11073 16-bit FLOAT, defined as a 16-bit vlue with 12-bit mantissa and
* 4-bit exponent. */
typedef struct
{
int8_t exponent; /**< Base 10 exponent, only 4 bits */
int16_t mantissa; /**< Mantissa, only 12 bits */
} ieee_float16_t;
/**@brief Blood Pressure Service init structure. This contains all options and data
* needed for initialization of the service. */
typedef struct
{
ble_bps_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Blood Pressure Service. */
ble_srv_cccd_security_mode_t bps_meas_attr_md; /**< Initial security level for blood pressure measurement attribute */
ble_srv_security_mode_t bps_feature_attr_md; /**< Initial security level for blood pressure feature attribute */
uint16_t feature; /**< Initial value for blood pressure feature */
} ble_bps_init_t;
/**@brief Blood Pressure Service structure. This contains various status information for
* the service. */
struct ble_bps_s
{
ble_bps_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Blood Pressure Service. */
uint16_t service_handle; /**< Handle of Blood Pressure Service (as provided by the BLE stack). */
ble_gatts_char_handles_t meas_handles; /**< Handles related to the Blood Pressure Measurement characteristic. */
ble_gatts_char_handles_t feature_handles; /**< Handles related to the Blood Pressure Feature characteristic. */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
uint16_t feature; /**< Value of Blood Pressure feature. */
};
/**@brief Blood Pressure Service measurement structure. This contains a Blood Pressure
* measurement. */
typedef struct ble_bps_meas_s
{
bool blood_pressure_units_in_kpa; /**< Blood Pressure Units Flag, 0=mmHg, 1=kPa */
bool time_stamp_present; /**< Time Stamp Flag, 0=not present, 1=present. */
bool pulse_rate_present; /**< Pulse Rate Flag, 0=not present, 1=present. */
bool user_id_present; /**< User ID Flag, 0=not present, 1=present. */
bool measurement_status_present; /**< Measurement Status Flag, 0=not present, 1=present. */
ieee_float16_t blood_pressure_systolic; /**< Blood Pressure Measurement Compound Value - Systolic. */
ieee_float16_t blood_pressure_diastolic; /**< Blood Pressure Measurement Compound Value - Diastolic . */
ieee_float16_t mean_arterial_pressure; /**< Blood Pressure Measurement Compound Value - Mean Arterial Pressure. */
ble_date_time_t time_stamp; /**< Time Stamp. */
ieee_float16_t pulse_rate; /**< Pulse Rate. */
uint8_t user_id; /**< User ID. */
uint16_t measurement_status; /**< Measurement Status. */
} ble_bps_meas_t;
/**@brief Function for initializing the Blood Pressure Service.
*
* @param[out] p_bps Blood Pressure Service structure. This structure will have to
* be supplied by the application. It will be initialized by this function,
* and will later be used to identify this particular service instance.
* @param[in] p_bps_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
*/
uint32_t ble_bps_init(ble_bps_t * p_bps, const ble_bps_init_t * p_bps_init);
/**@brief Function for handling the Application's BLE Stack events.
*
* @details Handles all events from the BLE stack of interest to the Blood Pressure Service.
*
* @param[in] p_bps Blood Pressure Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_bps_on_ble_evt(ble_bps_t * p_bps, ble_evt_t * p_ble_evt);
/**@brief Function for sending blood pressure measurement if indication has been enabled.
*
* @details The application calls this function after having performed a Blood Pressure
* measurement. If indication has been enabled, the measurement data is encoded and
* sent to the client.
*
* @param[in] p_bps Blood Pressure Service structure.
* @param[in] p_bps_meas Pointer to new blood pressure measurement.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
uint32_t ble_bps_measurement_send(ble_bps_t * p_bps, ble_bps_meas_t * p_bps_meas);
/**@brief Function for checking if indication of Blood Pressure Measurement is currently enabled.
*
* @param[in] p_bps Blood Pressure Service structure.
* @param[out] p_indication_enabled TRUE if indication is enabled, FALSE otherwise.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
uint32_t ble_bps_is_indication_enabled(ble_bps_t * p_bps, bool * p_indication_enabled);
#endif // BLE_BPS_H__
/** @} */

View File

@ -1,443 +0,0 @@
/* 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.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#include "ble_cscs.h"
#include <string.h>
#include "nordic_common.h"
#include "ble_l2cap.h"
#include "ble_srv_common.h"
#include "app_util.h"
#define OPCODE_LENGTH 1 /**< Length of opcode inside Cycling Speed and Cadence Measurement packet. */
#define HANDLE_LENGTH 2 /**< Length of handle inside Cycling Speed and Cadence Measurement packet. */
#define MAX_CSCM_LEN (BLE_L2CAP_MTU_DEF - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Cycling Speed and Cadence Measurement. */
// Cycling Speed and Cadence Measurement flag bits
#define CSC_MEAS_FLAG_MASK_WHEEL_REV_DATA_PRESENT (0x01 << 0) /**< Wheel revolution data present flag bit. */
#define CSC_MEAS_FLAG_MASK_CRANK_REV_DATA_PRESENT (0x01 << 1) /**< Crank revolution data present flag bit. */
/**@brief Function for handling the Connect event.
*
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_connect(ble_cscs_t * p_cscs, ble_evt_t * p_ble_evt)
{
p_cscs->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}
/**@brief Function for handling the Disconnect event.
*
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_disconnect(ble_cscs_t * p_cscs, ble_evt_t * p_ble_evt)
{
UNUSED_PARAMETER(p_ble_evt);
p_cscs->conn_handle = BLE_CONN_HANDLE_INVALID;
}
/**@brief Function for handling write events to the CSCS Measurement characteristic.
*
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
* @param[in] p_evt_write Write event received from the BLE stack.
*/
static void on_meas_cccd_write(ble_cscs_t * p_cscs, ble_gatts_evt_write_t * p_evt_write)
{
if (p_evt_write->len == 2)
{
// CCCD written, update notification state
if (p_cscs->evt_handler != NULL)
{
ble_cscs_evt_t evt;
if (ble_srv_is_notification_enabled(p_evt_write->data))
{
evt.evt_type = BLE_CSCS_EVT_NOTIFICATION_ENABLED;
}
else
{
evt.evt_type = BLE_CSCS_EVT_NOTIFICATION_DISABLED;
}
p_cscs->evt_handler(p_cscs, &evt);
}
}
}
/**@brief Function for handling the Write event.
*
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_write(ble_cscs_t * p_cscs, ble_evt_t * p_ble_evt)
{
ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
if (p_evt_write->handle == p_cscs->meas_handles.cccd_handle)
{
on_meas_cccd_write(p_cscs, p_evt_write);
}
}
void ble_cscs_on_ble_evt(ble_cscs_t * p_cscs, ble_evt_t * p_ble_evt)
{
ble_sc_ctrlpt_on_ble_evt(&(p_cscs->ctrl_pt), p_ble_evt);
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_cscs, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_cscs, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_cscs, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
/**@brief Function for encoding a CSCS Measurement.
*
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
* @param[in] p_csc_measurement Measurement to be encoded.
* @param[out] p_encoded_buffer Buffer where the encoded data will be written.
*
* @return Size of encoded data.
*/
static uint8_t csc_measurement_encode(ble_cscs_t * p_cscs,
ble_cscs_meas_t * p_csc_measurement,
uint8_t * p_encoded_buffer)
{
uint8_t flags = 0;
uint8_t len = 1;
// Cumulative Wheel Revolutions and Last Wheel Event Time Fields
if (p_cscs->feature & BLE_CSCS_FEATURE_WHEEL_REV_BIT)
{
if (p_csc_measurement->is_wheel_rev_data_present)
{
flags |= CSC_MEAS_FLAG_MASK_WHEEL_REV_DATA_PRESENT;
len += uint32_encode(p_csc_measurement->cumulative_wheel_revs, &p_encoded_buffer[len]);
len += uint16_encode(p_csc_measurement->last_wheel_event_time, &p_encoded_buffer[len]);
}
}
// Cumulative Crank Revolutions and Last Crank Event Time Fields
if (p_cscs->feature & BLE_CSCS_FEATURE_CRANK_REV_BIT)
{
if (p_csc_measurement->is_crank_rev_data_present)
{
flags |= CSC_MEAS_FLAG_MASK_CRANK_REV_DATA_PRESENT;
len += uint16_encode(p_csc_measurement->cumulative_crank_revs, &p_encoded_buffer[len]);
len += uint16_encode(p_csc_measurement->last_crank_event_time, &p_encoded_buffer[len]);
}
}
// Flags Field
p_encoded_buffer[0] = flags;
return len;
}
/**@brief Function for adding CSC Measurement characteristics.
*
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
* @param[in] p_cscs_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t csc_measurement_char_add(ble_cscs_t * p_cscs, const ble_cscs_init_t * p_cscs_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_md_t cccd_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
ble_cscs_meas_t initial_scm;
uint8_t encoded_scm[MAX_CSCM_LEN];
memset(&cccd_md, 0, sizeof(cccd_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
cccd_md.write_perm = p_cscs_init->csc_meas_attr_md.cccd_write_perm;
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.notify = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = &cccd_md;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_CSC_MEASUREMENT_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm );
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = csc_measurement_encode(p_cscs, &initial_scm, encoded_scm);
attr_char_value.init_offs = 0;
attr_char_value.max_len = MAX_CSCM_LEN;
attr_char_value.p_value = encoded_scm;
return sd_ble_gatts_characteristic_add(p_cscs->service_handle,
&char_md,
&attr_char_value,
&p_cscs->meas_handles);
}
/**@brief Function for adding CSC Feature characteristics.
*
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
* @param[in] p_cscs_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t csc_feature_char_add(ble_cscs_t * p_cscs, const ble_cscs_init_t * p_cscs_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
uint8_t init_value_encoded[2];
uint8_t init_value_len;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_CSC_FEATURE_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
attr_md.read_perm = p_cscs_init->csc_feature_attr_md.read_perm;
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 0;
memset(&attr_char_value, 0, sizeof(attr_char_value));
init_value_len = uint16_encode(p_cscs_init->feature, &init_value_encoded[0]);
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = init_value_len;
attr_char_value.init_offs = 0;
attr_char_value.max_len = init_value_len;
attr_char_value.p_value = init_value_encoded;
return sd_ble_gatts_characteristic_add(p_cscs->service_handle,
&char_md,
&attr_char_value,
&p_cscs->feature_handles);
}
/**@brief Function for adding CSC Sensor Location characteristic.
*
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
* @param[in] p_cscs_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t csc_sensor_loc_char_add(ble_cscs_t * p_cscs, const ble_cscs_init_t * p_cscs_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
uint8_t init_value_len;
uint8_t encoded_init_value[1];
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_SENSOR_LOCATION_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
attr_md.read_perm = p_cscs_init->csc_sensor_loc_attr_md.read_perm;
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 0;
memset(&attr_char_value, 0, sizeof(attr_char_value));
init_value_len = sizeof(uint8_t);
if (p_cscs_init->sensor_location != NULL)
{
encoded_init_value[0] = *p_cscs_init->sensor_location;
}
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = init_value_len;
attr_char_value.init_offs = 0;
attr_char_value.max_len = init_value_len;
attr_char_value.p_value = encoded_init_value;
return sd_ble_gatts_characteristic_add(p_cscs->service_handle,
&char_md,
&attr_char_value,
&p_cscs->sensor_loc_handles);
}
uint32_t ble_cscs_init(ble_cscs_t * p_cscs, const ble_cscs_init_t * p_cscs_init)
{
uint32_t err_code;
ble_uuid_t ble_uuid;
ble_cs_ctrlpt_init_t sc_ctrlpt_init;
// Initialize service structure
p_cscs->evt_handler = p_cscs_init->evt_handler;
p_cscs->conn_handle = BLE_CONN_HANDLE_INVALID;
p_cscs->feature = p_cscs_init->feature;
// Add service
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_CYCLING_SPEED_AND_CADENCE);
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
&ble_uuid,
&p_cscs->service_handle);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add cycling speed and cadence measurement characteristic
err_code = csc_measurement_char_add(p_cscs, p_cscs_init);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add cycling speed and cadence feature characteristic
err_code = csc_feature_char_add(p_cscs, p_cscs_init);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add Sensor Location characteristic (optional)
if (p_cscs_init->sensor_location != NULL)
{
err_code = csc_sensor_loc_char_add(p_cscs, p_cscs_init);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
// Add speed and cadence control point characteristic
sc_ctrlpt_init.error_handler = p_cscs_init->error_handler;
sc_ctrlpt_init.size_list_supported_locations = p_cscs_init->size_list_supported_locations;
sc_ctrlpt_init.supported_functions = p_cscs_init->ctrplt_supported_functions;
sc_ctrlpt_init.evt_handler = p_cscs_init->ctrlpt_evt_handler;
sc_ctrlpt_init.list_supported_locations = p_cscs_init->list_supported_locations;
sc_ctrlpt_init.sc_ctrlpt_attr_md = p_cscs_init->csc_ctrlpt_attr_md;
sc_ctrlpt_init.sensor_location_handle = p_cscs->sensor_loc_handles.value_handle;
sc_ctrlpt_init.service_handle = p_cscs->service_handle;
return ble_sc_ctrlpt_init(&p_cscs->ctrl_pt, &sc_ctrlpt_init);
}
uint32_t ble_cscs_measurement_send(ble_cscs_t * p_cscs, ble_cscs_meas_t * p_measurement)
{
uint32_t err_code;
// Send value if connected and notifying
if (p_cscs->conn_handle != BLE_CONN_HANDLE_INVALID)
{
uint8_t encoded_csc_meas[MAX_CSCM_LEN];
uint16_t len;
uint16_t hvx_len;
ble_gatts_hvx_params_t hvx_params;
len = csc_measurement_encode(p_cscs, p_measurement, encoded_csc_meas);
hvx_len = len;
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_cscs->meas_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
hvx_params.offset = 0;
hvx_params.p_len = &hvx_len;
hvx_params.p_data = encoded_csc_meas;
err_code = sd_ble_gatts_hvx(p_cscs->conn_handle, &hvx_params);
if ((err_code == NRF_SUCCESS) && (hvx_len != len))
{
err_code = NRF_ERROR_DATA_SIZE;
}
}
else
{
err_code = NRF_ERROR_INVALID_STATE;
}
return err_code;
}

View File

@ -1,161 +0,0 @@
/* 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_csc Cycling Speed and Cadence Service
* @{
* @ingroup ble_sdk_srv
* @brief Cycling Speed and Cadence Service module.
*
* @details This module implements the Cycling Speed and Cadence Service. If enabled, notification
* of the Cycling Speead and Candence Measurement is performed when the application
* calls ble_cscs_measurement_send().
*
* To use this service, you need to provide the the supported features (@ref BLE_CSCS_FEATURES).
* If you choose to support Wheel revolution data (feature bit @ref BLE_CSCS_FEATURE_WHEEL_REV_BIT),
* you then need to support the 'setting of cumulative value' operation by the supporting the
* Speed and Cadence Control Point (@ref ble_sdk_srv_sc_ctrlpt) by setting the @ref BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED
* bit of the ctrplt_supported_functions in the @ref ble_cscs_init_t structure.
* If you want to support the 'start autocalibration' control point feature, you need, after the @ref BLE_SC_CTRLPT_EVT_START_CALIBRATION
* has been received and the auto calibration is finished, to call the @ref ble_sc_ctrlpt_rsp_send to indicate that the operation is finished
* and thus be able to receive new control point operations.
* If you want to support the 'sensor location' related operation, you need to provide a list of supported location in the
* @ref ble_cscs_init_t structure.
*
*
* @note The application or the service using this module must propagate BLE stack events to the
* Cycling Speead and Candence Service module by calling ble_cscs_on_ble_evt() from the
* from the @ref softdevice_handler function. This service will forward the event to the @ref ble_sdk_srv_sc_ctrlpt module.
*
* @note Attention!
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_CSCS_H__
#define BLE_CSCS_H__
#include <stdint.h>
#include <stdbool.h>
#include "ble.h"
#include "ble_srv_common.h"
#include "ble_sc_ctrlpt.h"
#include "ble_sensor_location.h"
/** @defgroup BLE_CSCS_FEATURES Cycling Speed and Cadence Service feature bits
* @{ */
#define BLE_CSCS_FEATURE_WHEEL_REV_BIT (0x01 << 0) /**< Wheel Revolution Data Supported bit. */
#define BLE_CSCS_FEATURE_CRANK_REV_BIT (0x01 << 1) /**< Crank Revolution Data Supported bit. */
#define BLE_CSCS_FEATURE_MULTIPLE_SENSORS_BIT (0x01 << 2) /**< Multiple Sensor Locations Supported bit. */
/** @} */
/**@brief Cycling Speed and Cadence Service event type. */
typedef enum
{
BLE_CSCS_EVT_NOTIFICATION_ENABLED, /**< Cycling Speed and Cadence value notification enabled event. */
BLE_CSCS_EVT_NOTIFICATION_DISABLED /**< Cycling Speed and Cadence value notification disabled event. */
} ble_cscs_evt_type_t;
/**@brief Cycling Speed and Cadence Service event. */
typedef struct
{
ble_cscs_evt_type_t evt_type; /**< Type of event. */
} ble_cscs_evt_t;
// Forward declaration of the ble_csc_t type.
typedef struct ble_cscs_s ble_cscs_t;
/**@brief Cycling Speed and Cadence Service event handler type. */
typedef void (*ble_cscs_evt_handler_t) (ble_cscs_t * p_cscs, ble_cscs_evt_t * p_evt);
/**@brief Cycling Speed and Cadence Service init structure. This contains all options and data
* needed for initialization of the service. */
typedef struct
{
ble_cscs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Cycling Speed and Cadence Service. */
ble_srv_cccd_security_mode_t csc_meas_attr_md; /**< Initial security level for cycling speed and cadence measurement attribute */
ble_srv_cccd_security_mode_t csc_ctrlpt_attr_md; /**< Initial security level for cycling speed and cadence control point attribute */
ble_srv_security_mode_t csc_feature_attr_md; /**< Initial security level for feature attribute */
uint16_t feature; /**< Initial value for features of sensor @ref BLE_CSCS_FEATURES. */
uint8_t ctrplt_supported_functions; /**< Supported control point functionalities see @ref BLE_SRV_SC_CTRLPT_SUPP_FUNC. */
ble_sc_ctrlpt_evt_handler_t ctrlpt_evt_handler; /**< Event handler */
ble_sensor_location_t *list_supported_locations; /**< List of supported sensor locations.*/
uint8_t size_list_supported_locations; /**< Number of supported sensor locations in the list.*/
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
ble_sensor_location_t *sensor_location; /**< Initial Sensor Location, if NULL, sensor_location characteristic is not added*/
ble_srv_cccd_security_mode_t csc_sensor_loc_attr_md; /**< Initial security level for sensor location attribute */
} ble_cscs_init_t;
/**@brief Cycling Speed and Cadence Service structure. This contains various status information for
* the service. */
struct ble_cscs_s
{
ble_cscs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Cycling Speed and Cadence Service. */
uint16_t service_handle; /**< Handle of Cycling Speed and Cadence Service (as provided by the BLE stack). */
ble_gatts_char_handles_t meas_handles; /**< Handles related to the Cycling Speed and Cadence Measurement characteristic. */
ble_gatts_char_handles_t feature_handles; /**< Handles related to the Cycling Speed and Cadence feature characteristic. */
ble_gatts_char_handles_t sensor_loc_handles; /**< Handles related to the Cycling Speed and Cadence Sensor Location characteristic. */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
uint16_t feature; /**< Bit mask of features available on sensor. */
ble_sc_ctrlpt_t ctrl_pt; /**< data for speed and cadence control point */
};
/**@brief Cycling Speed and Cadence Service measurement structure. This contains a Cycling Speed and
* Cadence Service measurement. */
typedef struct ble_cscs_meas_s
{
bool is_wheel_rev_data_present; /**< True if Wheel Revolution Data is present in the measurement. */
bool is_crank_rev_data_present; /**< True if Crank Revolution Data is present in the measurement. */
uint32_t cumulative_wheel_revs; /**< Cumulative Wheel Revolutions. */
uint16_t last_wheel_event_time; /**< Last Wheel Event Time. */
uint16_t cumulative_crank_revs; /**< Cumulative Crank Revolutions. */
uint16_t last_crank_event_time; /**< Last Crank Event Time. */
} ble_cscs_meas_t;
/**@brief Function for initializing the Cycling Speed and Cadence Service.
*
* @param[out] p_cscs Cycling Speed and Cadence Service structure. This structure will have to
* be supplied by the application. It will be initialized by this function,
* and will later be used to identify this particular service instance.
* @param[in] p_cscs_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
*/
uint32_t ble_cscs_init(ble_cscs_t * p_cscs, const ble_cscs_init_t * p_cscs_init);
/**@brief Function for handling the Application's BLE Stack events.
*
* @details Handles all events from the BLE stack of interest to the Cycling Speed and Cadence
* Service.
*
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_cscs_on_ble_evt(ble_cscs_t * p_cscs, ble_evt_t * p_ble_evt);
/**@brief Function for sending cycling speed and cadence measurement if notification has been enabled.
*
* @details The application calls this function after having performed a Cycling Speed and Cadence
* Service measurement. If notification has been enabled, the measurement data is encoded
* and sent to the client.
*
* @param[in] p_cscs Cycling Speed and Cadence Service structure.
* @param[in] p_measurement Pointer to new cycling speed and cadence measurement.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
uint32_t ble_cscs_measurement_send(ble_cscs_t * p_cscs, ble_cscs_meas_t * p_measurement);
#endif // BLE_CSCS_H__
/** @} */

View File

@ -1,638 +0,0 @@
/* Copyright (c) 2013 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.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#include "ble_sc_ctrlpt.h"
#include <string.h>
#include "nordic_common.h"
#include "ble_l2cap.h"
#include "ble_srv_common.h"
#include "app_util.h"
#define SC_CTRLPT_NACK_PROC_ALREADY_IN_PROGRESS (BLE_GATT_STATUS_ATTERR_APP_BEGIN + 0)
#define SC_CTRLPT_NACK_CCCD_IMPROPERLY_CONFIGURED (BLE_GATT_STATUS_ATTERR_APP_BEGIN + 1)
uint32_t ble_sc_ctrlpt_init(ble_sc_ctrlpt_t * p_sc_ctrlpt,
const ble_cs_ctrlpt_init_t * p_sc_ctrlpt_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_md_t cccd_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
p_sc_ctrlpt->conn_handle = BLE_CONN_HANDLE_INVALID;
p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
p_sc_ctrlpt->size_list_supported_locations = p_sc_ctrlpt_init->size_list_supported_locations;
if ((p_sc_ctrlpt_init->size_list_supported_locations != 0) &&
(p_sc_ctrlpt_init->list_supported_locations != NULL))
{
memcpy(p_sc_ctrlpt->list_supported_locations,
p_sc_ctrlpt_init->list_supported_locations,
p_sc_ctrlpt->size_list_supported_locations * sizeof(ble_sensor_location_t));
}
p_sc_ctrlpt->service_handle = p_sc_ctrlpt_init->service_handle;
p_sc_ctrlpt->evt_handler = p_sc_ctrlpt_init->evt_handler;
p_sc_ctrlpt->supported_functions = p_sc_ctrlpt_init->supported_functions;
p_sc_ctrlpt->sensor_location_handle = p_sc_ctrlpt_init->sensor_location_handle;
p_sc_ctrlpt->error_handler = p_sc_ctrlpt_init->error_handler;
memset(&cccd_md, 0, sizeof(cccd_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
cccd_md.write_perm = p_sc_ctrlpt_init->sc_ctrlpt_attr_md.cccd_write_perm;
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.indicate = 1;
char_md.char_props.write = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = &cccd_md;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_SC_CTRLPT_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
attr_md.write_perm = p_sc_ctrlpt_init->sc_ctrlpt_attr_md.write_perm;
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 1;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = 0;
attr_char_value.init_offs = 0;
attr_char_value.max_len = BLE_SC_CTRLPT_MAX_LEN;
attr_char_value.p_value = 0;
return sd_ble_gatts_characteristic_add(p_sc_ctrlpt->service_handle,
&char_md,
&attr_char_value,
&p_sc_ctrlpt->sc_ctrlpt_handles);
}
/**@brief Decode an incoming control point write.
*
* @param[in] rcvd_val received write value
* @param[in] len value length
* @param[out] decoded_ctrlpt decoded control point structure
*/
static uint32_t sc_ctrlpt_decode(uint8_t * p_rcvd_val,
uint8_t len,
ble_sc_ctrlpt_val_t * p_write_val)
{
int pos = 0;
if (len < BLE_SC_CTRLPT_MIN_LEN)
{
return NRF_ERROR_INVALID_PARAM;
}
p_write_val->opcode = (ble_scpt_operator_t) p_rcvd_val[pos++];
switch (p_write_val->opcode)
{
case BLE_SCPT_REQUEST_SUPPORTED_SENSOR_LOCATIONS:
break;
case BLE_SCPT_START_AUTOMATIC_CALIBRATION:
break;
case BLE_SCPT_UPDATE_SENSOR_LOCATION:
p_write_val->location = (ble_sensor_location_t)p_rcvd_val[pos];
break;
case BLE_SCPT_SET_CUMULATIVE_VALUE:
p_write_val->cumulative_value = uint32_decode(&(p_rcvd_val[pos]));
break;
default:
return NRF_ERROR_INVALID_PARAM;
}
return NRF_SUCCESS;
}
/**@brief encode a control point response indication.
*
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
* @param[in] p_ctrlpt_rsp structure containing response data to be encoded
* @param[out] p_data pointer where data needs to be written
* @return size of encoded data
*/
static int ctrlpt_rsp_encode(ble_sc_ctrlpt_t * p_sc_ctrlpt,
ble_sc_ctrlpt_rsp_t * p_ctrlpt_rsp,
uint8_t * p_data)
{
int len = 0;
p_data[len++] = BLE_SCPT_RESPONSE_CODE;
p_data[len++] = p_ctrlpt_rsp->opcode;
p_data[len++] = p_ctrlpt_rsp->status;
if (p_ctrlpt_rsp->status == BLE_SCPT_SUCCESS)
{
switch (p_ctrlpt_rsp->opcode)
{
case BLE_SCPT_REQUEST_SUPPORTED_SENSOR_LOCATIONS:
{
int i;
for (i = 0; i < p_sc_ctrlpt->size_list_supported_locations; i++)
{
p_data[len++] = p_sc_ctrlpt->list_supported_locations[i];
}
break;
}
default:
// No implementation needed.
break;
}
}
return len;
}
/**@brief check if a given sensor location is supported or not.
*
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
* @param[in] location sensor location to check.
* @return true if the given location is found in the list of supported locations, false otherwise.
*/
static bool is_location_supported(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_sensor_location_t location)
{
int i;
for (i = 0; i < p_sc_ctrlpt->size_list_supported_locations; i++)
{
if (p_sc_ctrlpt->list_supported_locations[i] == location)
{
return true;
}
}
return false;
}
/**@brief check if the cccd is configured
*
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
* @return true if the sc_control point's cccd is correctly configured, false otherwise.
*/
static bool is_cccd_configured(ble_sc_ctrlpt_t * p_sc_ctrlpt)
{
uint32_t err_code;
uint8_t cccd_value_buf[BLE_CCCD_VALUE_LEN];
bool is_sccp_indic_enabled = false;
ble_gatts_value_t gatts_value;
// Initialize value struct.
memset(&gatts_value, 0, sizeof(gatts_value));
gatts_value.len = BLE_CCCD_VALUE_LEN;
gatts_value.offset = 0;
gatts_value.p_value = cccd_value_buf;
err_code = sd_ble_gatts_value_get(p_sc_ctrlpt->conn_handle,
p_sc_ctrlpt->sc_ctrlpt_handles.cccd_handle,
&gatts_value);
if (err_code != NRF_SUCCESS)
{
// Report error to application
if (p_sc_ctrlpt->error_handler != NULL)
{
p_sc_ctrlpt->error_handler(err_code);
}
}
is_sccp_indic_enabled = ble_srv_is_indication_enabled(cccd_value_buf);
return is_sccp_indic_enabled;
}
/**@brief sends a control point indication.
*
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
*/
static void sc_ctrlpt_resp_send(ble_sc_ctrlpt_t * p_sc_ctrlpt)
{
uint16_t hvx_len;
ble_gatts_hvx_params_t hvx_params;
uint32_t err_code;
if ((p_sc_ctrlpt->procedure_status == BLE_SCPT_INDICATION_PENDING))
{
hvx_len = p_sc_ctrlpt->response.len;
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_sc_ctrlpt->sc_ctrlpt_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_INDICATION;
hvx_params.offset = 0;
hvx_params.p_len = &hvx_len;
hvx_params.p_data = p_sc_ctrlpt->response.encoded_ctrl_rsp;
err_code = sd_ble_gatts_hvx(p_sc_ctrlpt->conn_handle, &hvx_params);
// Error handling
if ((err_code == NRF_SUCCESS) && (hvx_len != p_sc_ctrlpt->response.len))
{
err_code = NRF_ERROR_DATA_SIZE;
}
switch (err_code)
{
case NRF_SUCCESS:
p_sc_ctrlpt->procedure_status = BLE_SCPT_IND_CONFIRM_PENDING;
// Wait for HVC event
break;
case BLE_ERROR_NO_TX_PACKETS:
// Wait for TX_COMPLETE event to retry transmission
p_sc_ctrlpt->procedure_status = BLE_SCPT_INDICATION_PENDING;
break;
default:
// Report error to application
p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
if (p_sc_ctrlpt->error_handler != NULL)
{
p_sc_ctrlpt->error_handler(err_code);
}
break;
}
}
}
/**@brief Handle a write event to the Speed and Cadence Control Point.
*
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
* @param[in] p_evt_write WRITE event to be handled.
*/
static void on_ctrlpt_write(ble_sc_ctrlpt_t * p_sc_ctrlpt,
ble_gatts_evt_write_t * p_evt_write)
{
ble_sc_ctrlpt_val_t rcvd_ctrlpt =
{ BLE_SCPT_RESPONSE_CODE , 0, BLE_SENSOR_LOCATION_OTHER };
ble_sc_ctrlpt_rsp_t rsp;
uint32_t err_code;
ble_gatts_rw_authorize_reply_params_t auth_reply;
ble_sc_ctrlpt_evt_t evt;
auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
auth_reply.params.write.offset = 0;
auth_reply.params.write.len = 0;
auth_reply.params.write.p_data = NULL;
auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
auth_reply.params.write.update = 1;
if (is_cccd_configured(p_sc_ctrlpt))
{
if (p_sc_ctrlpt->procedure_status == BLE_SCPT_NO_PROC_IN_PROGRESS)
{
auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
}
else
{
auth_reply.params.write.gatt_status = SC_CTRLPT_NACK_PROC_ALREADY_IN_PROGRESS;
}
}
else
{
auth_reply.params.write.gatt_status = SC_CTRLPT_NACK_CCCD_IMPROPERLY_CONFIGURED;
}
err_code = sd_ble_gatts_rw_authorize_reply(p_sc_ctrlpt->conn_handle, &auth_reply);
if (err_code != NRF_SUCCESS)
{
// Report error to application.
if (p_sc_ctrlpt->error_handler != NULL)
{
p_sc_ctrlpt->error_handler(err_code);
}
}
if (auth_reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS)
{
return;
}
p_sc_ctrlpt->procedure_status = BLE_SCPT_INDICATION_PENDING;
rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
err_code = sc_ctrlpt_decode(p_evt_write->data, p_evt_write->len, &rcvd_ctrlpt);
if (err_code != NRF_SUCCESS)
{
rsp.opcode = rcvd_ctrlpt.opcode;
rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
}
else
{
rsp.opcode = rcvd_ctrlpt.opcode;
switch (rcvd_ctrlpt.opcode)
{
case BLE_SCPT_REQUEST_SUPPORTED_SENSOR_LOCATIONS:
if ((p_sc_ctrlpt->supported_functions &
BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) ==
BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED)
{
rsp.status = BLE_SCPT_SUCCESS;
}
else
{
rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
}
break;
case BLE_SCPT_UPDATE_SENSOR_LOCATION:
if ((p_sc_ctrlpt->supported_functions &
BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) ==
BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED)
{
if (is_location_supported(p_sc_ctrlpt, rcvd_ctrlpt.location))
{
ble_gatts_value_t gatts_value;
uint8_t rcvd_location = (uint8_t)rcvd_ctrlpt.location;
rsp.status = BLE_SCPT_SUCCESS;
// Initialize value struct.
memset(&gatts_value, 0, sizeof(gatts_value));
gatts_value.len = sizeof(uint8_t);
gatts_value.offset = 0;
gatts_value.p_value = &rcvd_location;
evt.evt_type = BLE_SC_CTRLPT_EVT_UPDATE_LOCATION;
evt.params.update_location = rcvd_ctrlpt.location;
if (p_sc_ctrlpt->evt_handler != NULL)
{
rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt);
}
if (rsp.status == BLE_SCPT_SUCCESS)
{
err_code = sd_ble_gatts_value_set(p_sc_ctrlpt->conn_handle,
p_sc_ctrlpt->sensor_location_handle,
&gatts_value);
if (err_code != NRF_SUCCESS)
{
// Report error to application
if (p_sc_ctrlpt->error_handler != NULL)
{
p_sc_ctrlpt->error_handler(err_code);
}
rsp.status = BLE_SCPT_OPERATION_FAILED;
}
}
}
else
{
rsp.status = BLE_SCPT_INVALID_PARAMETER;
}
}
else
{
rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
}
break;
case BLE_SCPT_SET_CUMULATIVE_VALUE:
if ((p_sc_ctrlpt->supported_functions &
BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED) ==
BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED)
{
rsp.status = BLE_SCPT_SUCCESS;
evt.evt_type = BLE_SC_CTRLPT_EVT_SET_CUMUL_VALUE;
evt.params.cumulative_value = rcvd_ctrlpt.cumulative_value;
if (p_sc_ctrlpt->evt_handler != NULL)
{
rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt);
}
}
else
{
rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
}
break;
case BLE_SCPT_START_AUTOMATIC_CALIBRATION:
if ((p_sc_ctrlpt->supported_functions &
BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED) ==
BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED)
{
p_sc_ctrlpt->procedure_status = BLE_SCPT_AUTOMATIC_CALIB_IN_PROGRESS;
evt.evt_type = BLE_SC_CTRLPT_EVT_START_CALIBRATION;
if (p_sc_ctrlpt->evt_handler != NULL)
{
rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt);
if (rsp.status != BLE_SCPT_SUCCESS)
{
p_sc_ctrlpt->procedure_status = BLE_SCPT_INDICATION_PENDING; // If the application returns an error, the response is to be sent right away and the calibration is considered as not started.
}
}
}
else
{
rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
}
break;
default:
rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
break;
}
}
p_sc_ctrlpt->response.len = ctrlpt_rsp_encode(p_sc_ctrlpt, &rsp,
p_sc_ctrlpt->response.encoded_ctrl_rsp);
if (p_sc_ctrlpt->procedure_status == BLE_SCPT_INDICATION_PENDING)
{
sc_ctrlpt_resp_send(p_sc_ctrlpt);
}
}
/**@brief Authorize WRITE request event handler.
*
* @details Handles WRITE events from the BLE stack.
*
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
* @param[in] p_gatts_evt GATTS Event received from the BLE stack.
*
*/
static void on_rw_authorize_request(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_gatts_evt_t * p_gatts_evt)
{
ble_gatts_evt_rw_authorize_request_t * p_auth_req = &p_gatts_evt->params.authorize_request;
if (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
{
if ( (p_gatts_evt->params.authorize_request.request.write.op
!= BLE_GATTS_OP_PREP_WRITE_REQ)
&& (p_gatts_evt->params.authorize_request.request.write.op
!= BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
&& (p_gatts_evt->params.authorize_request.request.write.op
!= BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)
)
{
if (p_auth_req->request.write.handle == p_sc_ctrlpt->sc_ctrlpt_handles.value_handle)
{
on_ctrlpt_write(p_sc_ctrlpt, &p_auth_req->request.write);
}
}
}
}
/**@brief Tx Complete event handler.
*
* @details Tx Complete event handler.
* Handles WRITE events from the BLE stack and if an indication was pending try sending it
* again.
*
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
*
*/
static void on_tx_complete(ble_sc_ctrlpt_t * p_sc_ctrlpt)
{
if (p_sc_ctrlpt->procedure_status == BLE_SCPT_INDICATION_PENDING)
{
sc_ctrlpt_resp_send(p_sc_ctrlpt);
}
}
/**@brief Function for handling the Connect event.
*
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_connect(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_evt_t * p_ble_evt)
{
p_sc_ctrlpt->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
}
/**@brief Function for handling the Disconnect event.
*
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_disconnect(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_evt_t * p_ble_evt)
{
UNUSED_PARAMETER(p_ble_evt);
p_sc_ctrlpt->conn_handle = BLE_CONN_HANDLE_INVALID;
p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
}
/**@brief Function for handling the BLE_GATTS_EVT_HVC event.
*
* @param[in] p_sc_ctrlpt SC Ctrlpt structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_sc_hvc_confirm(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_evt_t * p_ble_evt)
{
if (p_ble_evt->evt.gatts_evt.params.hvc.handle == p_sc_ctrlpt->sc_ctrlpt_handles.value_handle)
{
if (p_sc_ctrlpt->procedure_status == BLE_SCPT_IND_CONFIRM_PENDING)
{
p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
}
}
}
void ble_sc_ctrlpt_on_ble_evt(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_evt_t * p_ble_evt)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_sc_ctrlpt, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_sc_ctrlpt, p_ble_evt);
break;
case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
on_rw_authorize_request(p_sc_ctrlpt, &p_ble_evt->evt.gatts_evt);
break;
case BLE_GATTS_EVT_HVC:
on_sc_hvc_confirm(p_sc_ctrlpt, p_ble_evt);
break;
case BLE_EVT_TX_COMPLETE:
on_tx_complete(p_sc_ctrlpt);
break;
default:
break;
}
}
uint32_t ble_sc_ctrlpt_rsp_send(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_scpt_response_t response_status)
{
uint32_t err_code = NRF_SUCCESS;
ble_sc_ctrlpt_rsp_t rsp;
uint8_t encoded_ctrl_rsp[BLE_SC_CTRLPT_MAX_LEN];
uint16_t hvx_len;
ble_gatts_hvx_params_t hvx_params;
if (p_sc_ctrlpt->procedure_status != BLE_SCPT_AUTOMATIC_CALIB_IN_PROGRESS)
{
return NRF_ERROR_INVALID_STATE;
}
rsp.status = response_status;
rsp.opcode = BLE_SCPT_START_AUTOMATIC_CALIBRATION;
hvx_len = ctrlpt_rsp_encode(p_sc_ctrlpt, &rsp, encoded_ctrl_rsp);
// Send indication
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_sc_ctrlpt->sc_ctrlpt_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_INDICATION;
hvx_params.offset = 0;
hvx_params.p_len = &hvx_len;
hvx_params.p_data = encoded_ctrl_rsp;
err_code = sd_ble_gatts_hvx(p_sc_ctrlpt->conn_handle, &hvx_params);
if (err_code == NRF_SUCCESS)
{
p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
}
return err_code;
}

View File

@ -1,211 +0,0 @@
/* Copyright (c) 2013 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_sc_ctrlpt Speed and Cadence Control Point
* @{
* @ingroup ble_sdk_srv
* @brief Speed and Cadence Control Point module.
*
* @details This module implements the Speed and Cadence control point behavior. It is used
* by the @ref ble_sdk_srv_csc module and the ble_sdk_srv_rsc module for control point
* mechanisms like setting a cumulative value, Start an automatic calibration,
* Update the sensor location or request the supported locations.
*
* @note Attention!
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_SC_CTRLPT_H__
#define BLE_SC_CTRLPT_H__
#include <stdint.h>
#include <stdbool.h>
#include "ble.h"
#include "ble_srv_common.h"
#include "ble_sensor_location.h"
#define BLE_SC_CTRLPT_MAX_LEN 19 /**< maximum lenght for Speed and cadence control point characteristic value. */
#define BLE_SC_CTRLPT_MIN_LEN 1 /**< minimum length for Speed and cadence control point characteristic value. */
// Forward declaration of the ble_sc_ctrlpt_t type.
typedef struct ble_sc_ctrlpt_s ble_sc_ctrlpt_t;
/**@brief Speed and Cadence Control Point event type. */
typedef enum
{
BLE_SC_CTRLPT_EVT_UPDATE_LOCATION, /**< rcvd update location opcode (the control point handles the change of location automatically, the event just informs the application in case it needs to adjust its algorithm). */
BLE_SC_CTRLPT_EVT_SET_CUMUL_VALUE, /**< rcvd set cumulative value opcode, it is then up to the application to use the new cumulative value. */
BLE_SC_CTRLPT_EVT_START_CALIBRATION, /**< rcvd start calibration opcode, the application needs, at the end ot the calibration to call ble_sc_ctrlpt_send_rsp. */
} ble_sc_ctrlpt_evt_type_t;
/**@brief Speed and Cadence Control point event. */
typedef struct
{
ble_sc_ctrlpt_evt_type_t evt_type; /**< Type of event. */
union
{
ble_sensor_location_t update_location;
uint32_t cumulative_value;
}params;
} ble_sc_ctrlpt_evt_t;
/** Speed and Cadence Control Point operator code (see RSC service specification)*/
typedef enum {
BLE_SCPT_SET_CUMULATIVE_VALUE = 0x01, /**< Operator to set a given cumulative value. */
BLE_SCPT_START_AUTOMATIC_CALIBRATION = 0x02, /**< Operator to start automatic calibration. */
BLE_SCPT_UPDATE_SENSOR_LOCATION = 0x03, /**< Operator to update the sensor location. */
BLE_SCPT_REQUEST_SUPPORTED_SENSOR_LOCATIONS = 0x04, /**< Operator to request the supported sensor locations. */
BLE_SCPT_RESPONSE_CODE = 0x10, /**< Response Code. */
} ble_scpt_operator_t;
/** Speed and Cadence Control Point response parameter (see RSC service specification)*/
typedef enum {
BLE_SCPT_SUCCESS = 0x01, /**< Sucess Response. */
BLE_SCPT_OP_CODE_NOT_SUPPORTED = 0x02, /**< Error Response received opcode not supported. */
BLE_SCPT_INVALID_PARAMETER = 0x03, /**< Error Response received parameter invalid. */
BLE_SCPT_OPERATION_FAILED = 0x04, /**< Error Response operation failed. */
} ble_scpt_response_t;
/** Speed and Cadence Control Point procedure status (indicates is a procedure is in progress or not and which procedure is in progress*/
typedef enum {
BLE_SCPT_NO_PROC_IN_PROGRESS = 0x00, /**< No procedure in progress. */
BLE_SCPT_AUTOMATIC_CALIB_IN_PROGRESS = 0x01, /**< Automatic Calibration is in progress. */
BLE_SCPT_INDICATION_PENDING = 0x02, /**< Control Point Indication is pending. */
BLE_SCPT_IND_CONFIRM_PENDING = 0x03, /**< Waiting for the indication confirmation. */
}ble_scpt_procedure_status_t;
/**@brief Speed and Cadence Control point event handler type. */
typedef ble_scpt_response_t (*ble_sc_ctrlpt_evt_handler_t) (ble_sc_ctrlpt_t * p_sc_ctrlpt,
ble_sc_ctrlpt_evt_t * p_evt);
typedef struct{
ble_scpt_operator_t opcode;
uint32_t cumulative_value;
ble_sensor_location_t location;
}ble_sc_ctrlpt_val_t;
typedef struct{
ble_scpt_operator_t opcode;
ble_scpt_response_t status;
ble_sensor_location_t location_list[BLE_NB_MAX_SENSOR_LOCATIONS];
}ble_sc_ctrlpt_rsp_t;
/**
* \defgroup BLE_SRV_SC_CTRLPT_SUPP_FUNC Control point functionalities.
*@{
*/
#define BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED 0x01 /**< Support for sensor location related operations */
#define BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED 0x02 /**< Support for setting cumulative value related operations */
#define BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED 0x04 /**< Support for starting calibration related operations */
/**
*@}
*/
/**@brief Speed and Cadence Control Point init structure. This contains all options and data
* needed for initialization of the Speed and Cadence Control Point module. */
typedef struct
{
ble_srv_cccd_security_mode_t sc_ctrlpt_attr_md; /**< Initial security level for cycling speed and cadence control point attribute */
uint8_t supported_functions; /**< supported control point functionalities see @ref BLE_SRV_SC_CTRLPT_SUPP_FUNC. */
uint16_t service_handle; /**< Handle of the parent service (as provided by the BLE stack). */
ble_sc_ctrlpt_evt_handler_t evt_handler; /**< event handler */
ble_sensor_location_t *list_supported_locations; /**< list of supported sensor locations.*/
uint8_t size_list_supported_locations; /**< number of supported sensor locations in the list.*/
uint16_t sensor_location_handle; /**< handle for the sensor location characteristic (if sensor_location related operation are supported).*/
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
} ble_cs_ctrlpt_init_t;
/**@brief Speed and Cadence Control Point response indication structure. */
typedef struct
{
ble_scpt_response_t status; /**< control point response status .*/
uint8_t len; /**< control point response length .*/
uint8_t encoded_ctrl_rsp[BLE_SC_CTRLPT_MAX_LEN]; /**< control point encoded response.*/
}ble_sc_ctrlpt_resp_t;
/**@brief Speed and Cadence Control Point structure. This contains various status information for
* the Speed and Cadence Control Point behavior. */
struct ble_sc_ctrlpt_s
{
uint8_t supported_functions; /**< supported control point functionalities see @ref BLE_SRV_SC_CTRLPT_SUPP_FUNC. */
uint16_t service_handle; /**< Handle of the parent service (as provided by the BLE stack). */
ble_gatts_char_handles_t sc_ctrlpt_handles; /**< Handles related to the Speed and Cadence Control Point characteristic. */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
ble_sensor_location_t list_supported_locations[BLE_NB_MAX_SENSOR_LOCATIONS]; /**< list of supported sensor locations.*/
uint8_t size_list_supported_locations; /**< number of supported sensor locations in the list.*/
ble_sc_ctrlpt_evt_handler_t evt_handler; /**< Handle of the parent service (as provided by the BLE stack). */
uint16_t sensor_location_handle; /**< handle for the sensor location characteristic (if sensor_location related operation are supported).*/
ble_scpt_procedure_status_t procedure_status; /**< status of possible procedure*/
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
ble_sc_ctrlpt_resp_t response; /**< pending response data.*/
};
#define SCPT_OPCODE_POS 0 /**< Request opcode position. */
#define SCPT_PARAMETER_POS 1 /**< Request parameter position. */
#define SCPT_RESPONSE_REQUEST_OPCODE_POS 1 /**< Response position of requested opcode. */
#define SCPT_RESPONSE_CODE_POS 2 /**< Response position of response code. */
#define SCPT_RESPONSE_PARAMETER 3 /**< Response position of response parameter. */
#define SCPT_MIN_RESPONSE_SIZE 3 /**< Minimum size for control point response. */
#define SCPT_MAX_RESPONSE_SIZE (SCPT_MIN_RESPONSE_SIZE + NB_MAX_SENSOR_LOCATIONS) /**< Maximum size for control point response. */
/**@brief Function for Initializing the Speed and Cadence Control Point.
*
* @details Function for Initializing the Speed and Cadence Control Point.
* @param[in] p_sc_ctrlpt Speed and Cadence Control Point structure.
* @param[in] p_sc_ctrlpt_init Information needed to initialize the control point behavior.
*
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
*/
uint32_t ble_sc_ctrlpt_init(ble_sc_ctrlpt_t * p_sc_ctrlpt,
const ble_cs_ctrlpt_init_t * p_sc_ctrlpt_init);
/**@brief Function for sending a control point response.
*
* @details Function for sending a control point response when the control point received was
* BLE_SCPT_START_AUTOMATIC_CALIBRATION. To be called after the calibration procedure is finished.
*
* @param[in] p_sc_ctrlpt Speed and Cadence Control Point structure.
* @param[in] response_status status to include in the control point response.
*/
uint32_t ble_sc_ctrlpt_rsp_send(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_scpt_response_t response_status);
/**@brief Speed and Cadence Control Point BLE stack event handler.
*
* @details Handles all events from the BLE stack of interest to the Speed and Cadence Control Point.
*
* @param[in] p_sc_ctrlpt Speed and Cadence Control Point structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_sc_ctrlpt_on_ble_evt(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_evt_t * p_ble_evt);
#endif // BLE_SC_CTRLPT_H__
/** @} */

View File

@ -1,340 +0,0 @@
/* 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 <string.h>
#include "ble.h"
#include "ble_srv_common.h"
#include "ble_gattc.h"
#include "ble_cts_c.h"
#include "ble_date_time.h"
#include "ble_db_discovery.h"
#include "nrf_log.h"
#include "nrf_log.h"
#include "sdk_common.h"
#define CTS_LOG NRF_LOG_PRINTF_DEBUG /**< Debug logger macro that will be used in this file to do logging of important information over UART. */
#define CTS_YEAR_MIN 1582 /**< The lowest valid Current Time year is the year when the western calendar was introduced. */
#define CTS_YEAR_MAX 9999 /**< The highest possible Current Time. */
#define CTS_C_CURRENT_TIME_EXPECTED_LENGTH 10 /**< | Year |Month |Day |Hours |Minutes |Seconds |Weekday |Fraction|Reason |
| 2 bytes |1 byte |1 byte |1 byte |1 byte |1 byte |1 byte |1 byte |1 byte | = 10 bytes. */
/**@brief Function for handling events from the database discovery module.
*
* @details This function will handle an event from the database discovery module, and determine
* if it relates to the discovery of Current Time Service at the peer. If so, it will
* call the application's event handler indicating that the Current Time 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.
*
*/
void ble_cts_c_on_db_disc_evt(ble_cts_c_t * p_cts, ble_db_discovery_evt_t * p_evt)
{
CTS_LOG("[CTS]: Database Discovery handler called with event 0x%x\r\n", p_evt->evt_type);
ble_cts_c_evt_t evt;
const ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;
evt.evt_type = BLE_CTS_C_EVT_DISCOVERY_FAILED;
evt.conn_handle = p_evt->conn_handle;
// Check if the Current Time Service was discovered.
if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_CURRENT_TIME_SERVICE &&
p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
{
// Find the handles of the Current Time characteristic.
uint32_t i;
for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid ==
BLE_UUID_CURRENT_TIME_CHAR)
{
// Found Current Time characteristic. Store CCCD and value handle and break.
evt.params.char_handles.cts_handle = p_chars->characteristic.handle_value;
evt.params.char_handles.cts_cccd_handle = p_chars->cccd_handle;
break;
}
}
CTS_LOG("[CTS]: Current Time Service discovered at peer.\r\n");
evt.evt_type = BLE_CTS_C_EVT_DISCOVERY_COMPLETE;
}
p_cts->evt_handler(p_cts, &evt);
}
uint32_t ble_cts_c_init(ble_cts_c_t * p_cts, ble_cts_c_init_t const * p_cts_init)
{
//Verify that the parameters needed for to initialize this instance of CTS are not NULL.
VERIFY_PARAM_NOT_NULL(p_cts);
VERIFY_PARAM_NOT_NULL(p_cts_init);
VERIFY_PARAM_NOT_NULL(p_cts_init->error_handler);
VERIFY_PARAM_NOT_NULL(p_cts_init->evt_handler);
static ble_uuid_t cts_uuid;
BLE_UUID_BLE_ASSIGN(cts_uuid, BLE_UUID_CURRENT_TIME_SERVICE);
p_cts->evt_handler = p_cts_init->evt_handler;
p_cts->error_handler = p_cts_init->error_handler;
p_cts->conn_handle = BLE_CONN_HANDLE_INVALID;
p_cts->char_handles.cts_handle = BLE_GATT_HANDLE_INVALID;
p_cts->char_handles.cts_cccd_handle = BLE_GATT_HANDLE_INVALID;
return ble_db_discovery_evt_register(&cts_uuid);
}
/**@brief Function for decoding a read from the current time characteristic.
*
* @param[in] p_time Current Time structure.
* @param[in] p_data Pointer to the buffer containing the current time.
* @param[in] length length of the buffer containing the current time.
*
* @return NRF_SUCCESS if the time struct is valid.
* @return NRF_ERROR_DATA_SIZE if length does not match the expected size of the data.
*/
static uint32_t current_time_decode(current_time_char_t * p_time,
const uint8_t * p_data,
const uint32_t length)
{
//lint -save -e415 -e416 "Access of out of bounds pointer" "Creation of out of bounds pointer"
if (length != CTS_C_CURRENT_TIME_EXPECTED_LENGTH)
{
// Return to prevent accessing out of bounds data.
return NRF_ERROR_DATA_SIZE;
}
CTS_LOG("Current Time read response data: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X \r\n",
p_data[0],
p_data[1],
p_data[2],
p_data[3],
p_data[4],
p_data[5],
p_data[6],
p_data[7],
p_data[8],
p_data[9]);
uint32_t index = 0;
// Date.
index += ble_date_time_decode(&p_time->exact_time_256.day_date_time.date_time, p_data);
// Day of week.
p_time->exact_time_256.day_date_time.day_of_week = p_data[index++];
// Fractions of a second.
p_time->exact_time_256.fractions256 = p_data[index++];
// Reason for updating the time.
p_time->adjust_reason.manual_time_update = (p_data[index] >> 0) & 0x01;
p_time->adjust_reason.external_reference_time_update = (p_data[index] >> 1) & 0x01;
p_time->adjust_reason.change_of_time_zone = (p_data[index] >> 2) & 0x01;
p_time->adjust_reason.change_of_daylight_savings_time = (p_data[index] >> 3) & 0x01;
//lint -restore
return NRF_SUCCESS;
}
/**@brief Function for decoding a read from the current time characteristic.
*
* @param[in] p_time Current Time struct.
*
* @return NRF_SUCCESS if the time struct is valid.
* @return NRF_ERROR_INVALID_DATA if the time is out of bounds.
*/
static uint32_t current_time_validate(current_time_char_t * p_time)
{
// Year.
if ( (p_time->exact_time_256.day_date_time.date_time.year > CTS_YEAR_MAX)
|| ((p_time->exact_time_256.day_date_time.date_time.year < CTS_YEAR_MIN)
&& (p_time->exact_time_256.day_date_time.date_time.year != 0)))
{
return NRF_ERROR_INVALID_DATA;
}
// Month.
if (p_time->exact_time_256.day_date_time.date_time.month > 12)
{
return NRF_ERROR_INVALID_DATA;
}
// Day.
if (p_time->exact_time_256.day_date_time.date_time.day > 31)
{
return NRF_ERROR_INVALID_DATA;
}
// Hours.
if (p_time->exact_time_256.day_date_time.date_time.hours > 23)
{
return NRF_ERROR_INVALID_DATA;
}
// Minutes.
if (p_time->exact_time_256.day_date_time.date_time.minutes > 59)
{
return NRF_ERROR_INVALID_DATA;
}
// Seconds.
if (p_time->exact_time_256.day_date_time.date_time.seconds > 59)
{
return NRF_ERROR_INVALID_DATA;
}
// Day of week.
if (p_time->exact_time_256.day_date_time.day_of_week > 7)
{
return NRF_ERROR_INVALID_DATA;
}
return NRF_SUCCESS;
}
/**@brief Function for reading the current time. The time is decoded, then it is validated.
* Depending on the outcome the cts event handler will be called with
* the current time event or an invalid time event.
*
* @param[in] p_cts Current Time Service client structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void current_time_read(ble_cts_c_t * p_cts, const ble_evt_t * p_ble_evt)
{
ble_cts_c_evt_t evt;
uint32_t err_code = NRF_SUCCESS;
// Check if the event is on the same connection as this cts instance
if (p_cts->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
{
return;
}
if (p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_SUCCESS)
{
err_code = current_time_decode(&evt.params.current_time,
p_ble_evt->evt.gattc_evt.params.read_rsp.data,
p_ble_evt->evt.gattc_evt.params.read_rsp.len);
if (err_code != NRF_SUCCESS)
{
// The data length was invalid, decoding was not completed.
evt.evt_type = BLE_CTS_C_EVT_INVALID_TIME;
}
else
{
// Verify That the time is valid.
err_code = current_time_validate(&evt.params.current_time);
if (err_code != NRF_SUCCESS)
{
// Invalid time received.
evt.evt_type = BLE_CTS_C_EVT_INVALID_TIME;
}
else
{
// Valid time reveiced.
evt.evt_type = BLE_CTS_C_EVT_CURRENT_TIME;
}
}
p_cts->evt_handler(p_cts, &evt);
}
}
/**@brief Function for handling the Disconnect event.
*
* @param[in] p_cts Current Time Service client structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_disconnect(ble_cts_c_t * p_cts, ble_evt_t const * p_ble_evt)
{
if (p_cts->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
{
p_cts->conn_handle = BLE_CONN_HANDLE_INVALID;
}
if (ble_cts_c_is_cts_discovered(p_cts))
{
// There was a valid instance of cts on the peer. Send an event to the
// application, so that it can do any clean up related to this module.
ble_cts_c_evt_t evt;
evt.evt_type = BLE_CTS_C_EVT_DISCONN_COMPLETE;
p_cts->evt_handler(p_cts, &evt);
p_cts->char_handles.cts_handle = BLE_GATT_HANDLE_INVALID;
p_cts->char_handles.cts_cccd_handle = BLE_GATT_HANDLE_INVALID;
}
}
void ble_cts_c_on_ble_evt(ble_cts_c_t * p_cts, ble_evt_t const * p_ble_evt)
{
CTS_LOG("[CTS]: BLE event handler called with event 0x%x\r\n", p_ble_evt->header.evt_id);
switch (p_ble_evt->header.evt_id)
{
case BLE_GATTC_EVT_READ_RSP:
current_time_read(p_cts, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_cts, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
uint32_t ble_cts_c_current_time_read(ble_cts_c_t const * p_cts)
{
if (!ble_cts_c_is_cts_discovered(p_cts))
{
return NRF_ERROR_NOT_FOUND;
}
return sd_ble_gattc_read(p_cts->conn_handle, p_cts->char_handles.cts_handle, 0);
}
uint32_t ble_cts_c_handles_assign(ble_cts_c_t * p_cts,
const uint16_t conn_handle,
const ble_cts_c_handles_t * p_peer_handles)
{
VERIFY_PARAM_NOT_NULL(p_cts);
p_cts->conn_handle = conn_handle;
if (p_peer_handles != NULL)
{
p_cts->char_handles.cts_cccd_handle = p_peer_handles->cts_cccd_handle;
p_cts->char_handles.cts_handle = p_peer_handles->cts_handle;
}
return NRF_SUCCESS;
}

View File

@ -1,219 +0,0 @@
/* Copyright (c) 2014 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_cts_c Current Time Service client
* @{
* @ingroup ble_sdk_srv
* @brief Current Time Service client module.
*
* @details This module implements the Current Time Service (CTS) client-peripheral role of
* the Time Profile. After security is established, the module tries to discover the
* Current Time Service and Characteristic on the central side. If this succeeds,
* the application can trigger a read of the current time from the connected server.
*
* The module informs the application about a successful discovery using the
* @ref BLE_CTS_C_EVT_DISCOVERY_COMPLETE event. The handles for the CTS server is now
* available in the @ref ble_cts_c_evt_t structure. These handles must be assigned to an
* instance of CTS_C, using @ref ble_cts_c_handles_assign. For more information about
* service discovery, see the ble_discovery module documentation @ref lib_ble_db_discovery.
*
* The application can then use the function @ref ble_cts_c_current_time_read to read the
* current time. If the read succeeds, it will trigger either a
* @ref BLE_CTS_C_EVT_CURRENT_TIME event or a @ref BLE_CTS_C_EVT_INVALID_TIME event
* (depending on if the data that was read was actually a valid time), which is then sent
* to the application. The current time is then available in the params field of the
* passed @ref ble_cts_c_evt_t structure.
*
* @note The application must propagate BLE stack events to this module by calling
* ble_cts_c_on_ble_evt() from the @ref softdevice_handler callback function.
*/
#ifndef BLE_CTS_C_H__
#define BLE_CTS_C_H__
#include "ble_srv_common.h"
#include "ble_gattc.h"
#include "ble.h"
#include "ble_date_time.h"
#include "ble_db_discovery.h"
#include <stdint.h>
/**@brief "Day Date Time" field of the "Exact Time 256" field of the Current Time Characteristic. */
typedef struct
{
ble_date_time_t date_time;
uint8_t day_of_week;
} day_date_time_t;
/**@brief "Exact Time 256" field of the Current Time Characteristic. */
typedef struct
{
day_date_time_t day_date_time;
uint8_t fractions256;
} exact_time_256_t;
/**@brief "Adjust Reason" field of the Current Time Characteristic. */
typedef struct
{
uint8_t manual_time_update : 1;
uint8_t external_reference_time_update : 1;
uint8_t change_of_time_zone : 1;
uint8_t change_of_daylight_savings_time : 1;
} adjust_reason_t;
/**@brief Data structure for the Current Time Characteristic. */
typedef struct
{
exact_time_256_t exact_time_256;
adjust_reason_t adjust_reason;
} current_time_char_t;
// Forward declaration of the ble_cts_c_t type.
typedef struct ble_cts_c_s ble_cts_c_t;
/**@brief Current Time Service client event type. */
typedef enum
{
BLE_CTS_C_EVT_DISCOVERY_COMPLETE, /**< The Current Time Service was found at the peer. */
BLE_CTS_C_EVT_DISCOVERY_FAILED, /**< The Current Time Service was not found at the peer. */
BLE_CTS_C_EVT_DISCONN_COMPLETE, /**< Event indicating that the Current Time Service client module has finished processing the BLE_GAP_EVT_DISCONNECTED event. This event is raised only if a valid instance of the Current Time Service was found at the server. The event can be used by the application to do clean up related to the Current Time Service client.*/
BLE_CTS_C_EVT_CURRENT_TIME, /**< A new current time reading has been received. */
BLE_CTS_C_EVT_INVALID_TIME /**< The current time value received from the peer is invalid.*/
} ble_cts_c_evt_type_t;
/**@brief Structure containing the handles related to the Heart Rate Service found on the peer. */
typedef struct
{
uint16_t cts_handle; /**< Handle of the Current Time characteristic as provided by the SoftDevice. */
uint16_t cts_cccd_handle; /**< Handle of the CCCD of the Current Time characteristic. */
} ble_cts_c_handles_t;
/**@brief Current Time Service client event. */
typedef struct
{
ble_cts_c_evt_type_t evt_type; /**< Type of event. */
uint16_t conn_handle; /**< Connection handle on which the CTS service was discovered on the peer device. This will be filled if the evt_type is @ref BLE_CTS_C_EVT_DISCOVERY_COMPLETE.*/
union
{
current_time_char_t current_time; /**< Current Time Characteristic data. This will be filled when the evt_type is @ref BLE_CTS_C_EVT_CURRENT_TIME. */
ble_cts_c_handles_t char_handles; /**< Current Time related handles found on the peer device. This will be filled when the evt_type is @ref BLE_HRS_C_EVT_DISCOVERY_COMPLETE.*/
} params;
} ble_cts_c_evt_t;
/**@brief Current Time Service client event handler type. */
typedef void (* ble_cts_c_evt_handler_t) (ble_cts_c_t * p_cts, ble_cts_c_evt_t * p_evt);
/**@brief Current Time Service client structure. This structure contains status information for the client. */
struct ble_cts_c_s
{
ble_cts_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events from the Current Time Service client. */
ble_srv_error_handler_t error_handler; /**< Function to be called if an error occurs. */
ble_cts_c_handles_t char_handles; /**< Handles of Current Time Characteristic at the peer (handles are provided by the BLE stack through the DB Discovery module). */
uint16_t conn_handle; /**< Handle of the current connection. BLE_CONN_HANDLE_INVALID if not in a connection. */
};
/**@brief Current Time Service client init structure. This structure contains all options and data needed for initialization of the client.*/
typedef struct
{
ble_cts_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events from the Current Time Service client. */
ble_srv_error_handler_t error_handler; /**< Function to be called if an error occurs. */
} ble_cts_c_init_t;
/**@brief Function for initializing the Current Time Service client.
*
* @details This function must be used by the application to initialize the Current Time Service client.
*
* @param[out] p_cts Current Time Service client structure. This structure must
* be supplied by the application. It is initialized by this
* function and can later be used to identify this particular client
* instance.
* @param[in] p_cts_init Information needed to initialize the Current Time Service client.
*
* @retval NRF_SUCCESS If the service was initialized successfully.
*/
uint32_t ble_cts_c_init(ble_cts_c_t * p_cts, const ble_cts_c_init_t * p_cts_init);
/**@brief Function for handling events from the database discovery module.
*
* @details This function will handle an event from the database discovery module, and determine
* if it relates to the discovery of CTS at the peer. If so, it will
* call the application's event handler indicating that CTS has been
* discovered. It also populates the event with the service related
* information before providing it to the application.
*
* @param[in] p_cts Pointer to the CTS client structure.
* @param[in] p_evt Pointer to the event received from the database discovery module.
*/
void ble_cts_c_on_db_disc_evt(ble_cts_c_t * p_cts, ble_db_discovery_evt_t * p_evt);
/**@brief Function for handling the application's BLE stack events.
*
* @details This function handles all events from the BLE stack that are of interest to the
* Current Time Service client. This is a callback function that must be dispatched
* from main application context.
*
* @param[in] p_cts Current Time Service client structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_cts_c_on_ble_evt(ble_cts_c_t * p_cts, const ble_evt_t * p_ble_evt);
/**@brief Function for checking whether the peer's Current Time Service instance and the Current Time
* Characteristic have been discovered.
*
* @param[in] p_cts Current Time Service client structure.
*/
static __INLINE bool ble_cts_c_is_cts_discovered(const ble_cts_c_t * p_cts)
{
return (p_cts->char_handles.cts_handle != BLE_GATT_HANDLE_INVALID);
}
/**@brief Function for reading the peer's Current Time Service Current Time Characteristic.
*
* @param[in] p_cts Current Time Service client structure.
*
* @retval NRF_SUCCESS If the operation is successful. Otherwise, an error code is returned.
*/
uint32_t ble_cts_c_current_time_read(ble_cts_c_t const * p_cts);
/**@brief Function for assigning handles to a this instance of cts_c.
*
* @details Call this function when a link has been established with a peer to
* associate the link to this instance of the module. This makes it
* possible to handle several links and associate each link to a particular
* instance of this module. The connection handle and attribute handles will be
* provided from the discovery event @ref BLE_CTS_C_EVT_DISCOVERY_COMPLETE.
*
* @param[in] p_cts Pointer to the CTS client structure instance to associate.
* @param[in] conn_handle Connection handle to associated with the given CTS instance.
* @param[in] p_peer_handles Attribute handles for the CTS server you want this CTS client to
* interact with.
*
* @retval NRF_SUCCESS If the operation was successful.
* @retval NRF_ERROR_NULL If a p_cts was a NULL pointer.
*/
uint32_t ble_cts_c_handles_assign(ble_cts_c_t * p_cts,
const uint16_t conn_handle,
const ble_cts_c_handles_t * p_peer_handles);
#endif // BLE_CTS_C_H__
/** @} */

View File

@ -1,277 +0,0 @@
/* 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.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#include "ble_dis.h"
#include <stdlib.h>
#include <string.h>
#include "app_error.h"
#include "ble_gatts.h"
#include "nordic_common.h"
#include "ble_srv_common.h"
#include "app_util.h"
#define BLE_DIS_SYS_ID_LEN 8 /**< Length of System ID Characteristic Value. */
#define BLE_DIS_PNP_ID_LEN 7 /**< Length of Pnp ID Characteristic Value. */
static uint16_t service_handle;
static ble_gatts_char_handles_t manufact_name_handles;
static ble_gatts_char_handles_t model_num_handles;
static ble_gatts_char_handles_t serial_num_handles;
static ble_gatts_char_handles_t hw_rev_handles;
static ble_gatts_char_handles_t fw_rev_handles;
static ble_gatts_char_handles_t sw_rev_handles;
static ble_gatts_char_handles_t sys_id_handles;
static ble_gatts_char_handles_t reg_cert_data_list_handles;
static ble_gatts_char_handles_t pnp_id_handles;
/**@brief Function for encoding a System ID.
*
* @param[out] p_encoded_buffer Buffer where the encoded data will be written.
* @param[in] p_sys_id System ID to be encoded.
*/
static void sys_id_encode(uint8_t * p_encoded_buffer, const ble_dis_sys_id_t * p_sys_id)
{
APP_ERROR_CHECK_BOOL(p_sys_id != NULL);
APP_ERROR_CHECK_BOOL(p_encoded_buffer != NULL);
p_encoded_buffer[0] = (p_sys_id->manufacturer_id & 0x00000000FF);
p_encoded_buffer[1] = (p_sys_id->manufacturer_id & 0x000000FF00) >> 8;
p_encoded_buffer[2] = (p_sys_id->manufacturer_id & 0x0000FF0000) >> 16;
p_encoded_buffer[3] = (p_sys_id->manufacturer_id & 0x00FF000000) >> 24;
p_encoded_buffer[4] = (p_sys_id->manufacturer_id & 0xFF00000000) >> 32;
p_encoded_buffer[5] = (p_sys_id->organizationally_unique_id & 0x0000FF);
p_encoded_buffer[6] = (p_sys_id->organizationally_unique_id & 0x00FF00) >> 8;
p_encoded_buffer[7] = (p_sys_id->organizationally_unique_id & 0xFF0000) >> 16;
}
/**@brief Function for encoding a PnP ID.
*
* @param[out] p_encoded_buffer Buffer where the encoded data will be written.
* @param[in] p_pnp_id PnP ID to be encoded.
*/
static void pnp_id_encode(uint8_t * p_encoded_buffer, const ble_dis_pnp_id_t * p_pnp_id)
{
uint8_t len = 0;
APP_ERROR_CHECK_BOOL(p_pnp_id != NULL);
APP_ERROR_CHECK_BOOL(p_encoded_buffer != NULL);
p_encoded_buffer[len++] = p_pnp_id->vendor_id_source;
len += uint16_encode(p_pnp_id->vendor_id, &p_encoded_buffer[len]);
len += uint16_encode(p_pnp_id->product_id, &p_encoded_buffer[len]);
len += uint16_encode(p_pnp_id->product_version, &p_encoded_buffer[len]);
APP_ERROR_CHECK_BOOL(len == BLE_DIS_PNP_ID_LEN);
}
/**@brief Function for adding the Characteristic.
*
* @param[in] uuid UUID of characteristic to be added.
* @param[in] p_char_value Initial value of characteristic to be added.
* @param[in] char_len Length of initial value. This will also be the maximum value.
* @param[in] dis_attr_md Security settings of characteristic to be added.
* @param[out] p_handles Handles of new characteristic.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t char_add(uint16_t uuid,
uint8_t * p_char_value,
uint16_t char_len,
const ble_srv_security_mode_t * dis_attr_md,
ble_gatts_char_handles_t * p_handles)
{
ble_uuid_t ble_uuid;
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_gatts_attr_md_t attr_md;
APP_ERROR_CHECK_BOOL(p_char_value != NULL);
APP_ERROR_CHECK_BOOL(char_len > 0);
// The ble_gatts_char_md_t structure uses bit fields. So we reset the memory to zero.
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, uuid);
memset(&attr_md, 0, sizeof(attr_md));
attr_md.read_perm = dis_attr_md->read_perm;
attr_md.write_perm = dis_attr_md->write_perm;
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 0;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = char_len;
attr_char_value.init_offs = 0;
attr_char_value.max_len = char_len;
attr_char_value.p_value = p_char_value;
return sd_ble_gatts_characteristic_add(service_handle, &char_md, &attr_char_value, p_handles);
}
uint32_t ble_dis_init(const ble_dis_init_t * p_dis_init)
{
uint32_t err_code;
ble_uuid_t ble_uuid;
// Add service
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_DEVICE_INFORMATION_SERVICE);
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &service_handle);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add characteristics
if (p_dis_init->manufact_name_str.length > 0)
{
err_code = char_add(BLE_UUID_MANUFACTURER_NAME_STRING_CHAR,
p_dis_init->manufact_name_str.p_str,
p_dis_init->manufact_name_str.length,
&p_dis_init->dis_attr_md,
&manufact_name_handles);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
if (p_dis_init->model_num_str.length > 0)
{
err_code = char_add(BLE_UUID_MODEL_NUMBER_STRING_CHAR,
p_dis_init->model_num_str.p_str,
p_dis_init->model_num_str.length,
&p_dis_init->dis_attr_md,
&model_num_handles);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
if (p_dis_init->serial_num_str.length > 0)
{
err_code = char_add(BLE_UUID_SERIAL_NUMBER_STRING_CHAR,
p_dis_init->serial_num_str.p_str,
p_dis_init->serial_num_str.length,
&p_dis_init->dis_attr_md,
&serial_num_handles);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
if (p_dis_init->hw_rev_str.length > 0)
{
err_code = char_add(BLE_UUID_HARDWARE_REVISION_STRING_CHAR,
p_dis_init->hw_rev_str.p_str,
p_dis_init->hw_rev_str.length,
&p_dis_init->dis_attr_md,
&hw_rev_handles);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
if (p_dis_init->fw_rev_str.length > 0)
{
err_code = char_add(BLE_UUID_FIRMWARE_REVISION_STRING_CHAR,
p_dis_init->fw_rev_str.p_str,
p_dis_init->fw_rev_str.length,
&p_dis_init->dis_attr_md,
&fw_rev_handles);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
if (p_dis_init->sw_rev_str.length > 0)
{
err_code = char_add(BLE_UUID_SOFTWARE_REVISION_STRING_CHAR,
p_dis_init->sw_rev_str.p_str,
p_dis_init->sw_rev_str.length,
&p_dis_init->dis_attr_md,
&sw_rev_handles);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
if (p_dis_init->p_sys_id != NULL)
{
uint8_t encoded_sys_id[BLE_DIS_SYS_ID_LEN];
sys_id_encode(encoded_sys_id, p_dis_init->p_sys_id);
err_code = char_add(BLE_UUID_SYSTEM_ID_CHAR,
encoded_sys_id,
BLE_DIS_SYS_ID_LEN,
&p_dis_init->dis_attr_md,
&sys_id_handles);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
if (p_dis_init->p_reg_cert_data_list != NULL)
{
err_code = char_add(BLE_UUID_IEEE_REGULATORY_CERTIFICATION_DATA_LIST_CHAR,
p_dis_init->p_reg_cert_data_list->p_list,
p_dis_init->p_reg_cert_data_list->list_len,
&p_dis_init->dis_attr_md,
&reg_cert_data_list_handles);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
if (p_dis_init->p_pnp_id != NULL)
{
uint8_t encoded_pnp_id[BLE_DIS_PNP_ID_LEN];
pnp_id_encode(encoded_pnp_id, p_dis_init->p_pnp_id);
err_code = char_add(BLE_UUID_PNP_ID_CHAR,
encoded_pnp_id,
BLE_DIS_PNP_ID_LEN,
&p_dis_init->dis_attr_md,
&pnp_id_handles);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
return NRF_SUCCESS;
}

View File

@ -1,98 +0,0 @@
/* 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_dis Device Information Service
* @{
* @ingroup ble_sdk_srv
* @brief Device Information Service module.
*
* @details This module implements the Device Information Service.
* During initialization it adds the Device Information Service to the BLE stack database.
* It then encodes the supplied information, and adds the curresponding characteristics.
*
* @note Attention!
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_DIS_H__
#define BLE_DIS_H__
#include <stdint.h>
#include "ble_srv_common.h"
/** @defgroup DIS_VENDOR_ID_SRC_VALUES Vendor ID Source values
* @{
*/
#define BLE_DIS_VENDOR_ID_SRC_BLUETOOTH_SIG 1 /**< Vendor ID assigned by Bluetooth SIG. */
#define BLE_DIS_VENDOR_ID_SRC_USB_IMPL_FORUM 2 /**< Vendor ID assigned by USB Implementer's Forum. */
/** @} */
/**@brief System ID parameters */
typedef struct
{
uint64_t manufacturer_id; /**< Manufacturer ID. Only 5 LSOs shall be used. */
uint32_t organizationally_unique_id; /**< Organizationally unique ID. Only 3 LSOs shall be used. */
} ble_dis_sys_id_t;
/**@brief IEEE 11073-20601 Regulatory Certification Data List Structure */
typedef struct
{
uint8_t * p_list; /**< Pointer the byte array containing the encoded opaque structure based on IEEE 11073-20601 specification. */
uint8_t list_len; /**< Length of the byte array. */
} ble_dis_reg_cert_data_list_t;
/**@brief PnP ID parameters */
typedef struct
{
uint8_t vendor_id_source; /**< Vendor ID Source. see @ref DIS_VENDOR_ID_SRC_VALUES. */
uint16_t vendor_id; /**< Vendor ID. */
uint16_t product_id; /**< Product ID. */
uint16_t product_version; /**< Product Version. */
} ble_dis_pnp_id_t;
/**@brief Device Information Service init structure. This contains all possible characteristics
* needed for initialization of the service.
*/
typedef struct
{
ble_srv_utf8_str_t manufact_name_str; /**< Manufacturer Name String. */
ble_srv_utf8_str_t model_num_str; /**< Model Number String. */
ble_srv_utf8_str_t serial_num_str; /**< Serial Number String. */
ble_srv_utf8_str_t hw_rev_str; /**< Hardware Revision String. */
ble_srv_utf8_str_t fw_rev_str; /**< Firmware Revision String. */
ble_srv_utf8_str_t sw_rev_str; /**< Software Revision String. */
ble_dis_sys_id_t * p_sys_id; /**< System ID. */
ble_dis_reg_cert_data_list_t * p_reg_cert_data_list; /**< IEEE 11073-20601 Regulatory Certification Data List. */
ble_dis_pnp_id_t * p_pnp_id; /**< PnP ID. */
ble_srv_security_mode_t dis_attr_md; /**< Initial Security Setting for Device Information Characteristics. */
} ble_dis_init_t;
/**@brief Function for initializing the Device Information Service.
*
* @details This call allows the application to initialize the device information service.
* It adds the DIS service and DIS characteristics to the database, using the initial
* values supplied through the p_dis_init parameter. Characteristics which are not to be
* added, shall be set to NULL in p_dis_init.
*
* @param[in] p_dis_init The structure containing the values of characteristics needed by the
* service.
*
* @return NRF_SUCCESS on successful initialization of service.
*/
uint32_t ble_dis_init(const ble_dis_init_t * p_dis_init);
#endif // BLE_DIS_H__
/** @} */

View File

@ -1,264 +0,0 @@
/* 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.
*/
/** @file
*
* @defgroup ble_sdk_srv_gls Glucose Service
* @{
* @ingroup ble_sdk_srv
* @brief Glucose Service module.
*
* @details This module implements the Glucose Service.
*
* @note The application must propagate BLE stack events to the Glucose Service module by calling
* ble_gls_on_ble_evt() from the @ref softdevice_handler callback.
*
* @note Attention!
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_GLS_H__
#define BLE_GLS_H__
#include <stdint.h>
#include <stdbool.h>
#include "ble.h"
#include "ble_srv_common.h"
#include "ble_date_time.h"
/**@brief Glucose feature */
#define BLE_GLS_FEATURE_LOW_BATT 0x0001 /**< Low Battery Detection During Measurement Supported */
#define BLE_GLS_FEATURE_MALFUNC 0x0002 /**< Sensor Malfunction Detection Supported */
#define BLE_GLS_FEATURE_SAMPLE_SIZE 0x0004 /**< Sensor Sample Size Supported */
#define BLE_GLS_FEATURE_INSERT_ERR 0x0008 /**< Sensor Strip Insertion Error Detection Supported */
#define BLE_GLS_FEATURE_TYPE_ERR 0x0010 /**< Sensor Strip Type Error Detection Supported */
#define BLE_GLS_FEATURE_RES_HIGH_LOW 0x0020 /**< Sensor Result High-Low Detection Supported */
#define BLE_GLS_FEATURE_TEMP_HIGH_LOW 0x0040 /**< Sensor Temperature High-Low Detection Supported */
#define BLE_GLS_FEATURE_READ_INT 0x0080 /**< Sensor Read Interrupt Detection Supported */
#define BLE_GLS_FEATURE_GENERAL_FAULT 0x0100 /**< General Device Fault Supported */
#define BLE_GLS_FEATURE_TIME_FAULT 0x0200 /**< Time Fault Supported */
#define BLE_GLS_FEATURE_MULTI_BOND 0x0400 /**< Multiple Bond Supported */
/**@brief Glucose measurement flags */
#define BLE_GLS_MEAS_FLAG_TIME_OFFSET 0x01 /**< Time Offset Present */
#define BLE_GLS_MEAS_FLAG_CONC_TYPE_LOC 0x02 /**< Glucose Concentration, Type, and Sample Location Present */
#define BLE_GLS_MEAS_FLAG_UNITS_KG_L 0x00 /**< Glucose Concentration Units kg/L */
#define BLE_GLS_MEAS_FLAG_UNITS_MOL_L 0x04 /**< Glucose Concentration Units mol/L */
#define BLE_GLS_MEAS_FLAG_SENSOR_STATUS 0x08 /**< Sensor Status Annunciation Present */
#define BLE_GLS_MEAS_FLAG_CONTEXT_INFO 0x10 /**< Context Information Follows */
/**@brief Glucose measurement type */
#define BLE_GLS_MEAS_TYPE_CAP_BLOOD 1 /**< Capillary whole blood */
#define BLE_GLS_MEAS_TYPE_CAP_PLASMA 2 /**< Capillary plasma */
#define BLE_GLS_MEAS_TYPE_VEN_BLOOD 3 /**< Venous whole blood */
#define BLE_GLS_MEAS_TYPE_VEN_PLASMA 4 /**< Venous plasma */
#define BLE_GLS_MEAS_TYPE_ART_BLOOD 5 /**< Arterial whole blood */
#define BLE_GLS_MEAS_TYPE_ART_PLASMA 6 /**< Arterial plasma */
#define BLE_GLS_MEAS_TYPE_UNDET_BLOOD 7 /**< Undetermined whole blood */
#define BLE_GLS_MEAS_TYPE_UNDET_PLASMA 8 /**< Undetermined plasma */
#define BLE_GLS_MEAS_TYPE_FLUID 9 /**< Interstitial fluid (ISF) */
#define BLE_GLS_MEAS_TYPE_CONTROL 10 /**< Control solution */
/**@brief Glucose measurement location */
#define BLE_GLS_MEAS_LOC_FINGER 1 /**< Finger */
#define BLE_GLS_MEAS_LOC_AST 2 /**< Alternate Site Test (AST) */
#define BLE_GLS_MEAS_LOC_EAR 3 /**< Earlobe */
#define BLE_GLS_MEAS_LOC_CONTROL 4 /**< Control solution */
#define BLE_GLS_MEAS_LOC_NOT_AVAIL 15 /**< Sample Location value not available */
/**@brief Glucose sensor status annunciation */
#define BLE_GLS_MEAS_STATUS_BATT_LOW 0x0001 /**< Device battery low at time of measurement */
#define BLE_GLS_MEAS_STATUS_SENSOR_FAULT 0x0002 /**< Sensor malfunction or faulting at time of measurement */
#define BLE_GLS_MEAS_STATUS_SAMPLE_SIZE 0x0004 /**< Sample size for blood or control solution insufficient at time of measurement */
#define BLE_GLS_MEAS_STATUS_STRIP_INSERT 0x0008 /**< Strip insertion error */
#define BLE_GLS_MEAS_STATUS_STRIP_TYPE 0x0010 /**< Strip type incorrect for device */
#define BLE_GLS_MEAS_STATUS_RESULT_HIGH 0x0020 /**< Sensor result higher than the device can process */
#define BLE_GLS_MEAS_STATUS_RESULT_LOW 0x0040 /**< Sensor result lower than the device can process */
#define BLE_GLS_MEAS_STATUS_TEMP_HIGH 0x0080 /**< Sensor temperature too high for valid test/result at time of measurement */
#define BLE_GLS_MEAS_STATUS_TEMP_LOW 0x0100 /**< Sensor temperature too low for valid test/result at time of measurement */
#define BLE_GLS_MEAS_STATUS_STRIP_PULL 0x0200 /**< Sensor read interrupted because strip was pulled too soon at time of measurement */
#define BLE_GLS_MEAS_STATUS_GENERAL_FAULT 0x0400 /**< General device fault has occurred in the sensor */
#define BLE_GLS_MEAS_STATUS_TIME_FAULT 0x0800 /**< Time fault has occurred in the sensor and time may be inaccurate */
/**@brief Glucose measurement context flags */
#define BLE_GLS_CONTEXT_FLAG_CARB 0x01 /**< Carbohydrate id and carbohydrate present */
#define BLE_GLS_CONTEXT_FLAG_MEAL 0x02 /**< Meal present */
#define BLE_GLS_CONTEXT_FLAG_TESTER 0x04 /**< Tester-health present */
#define BLE_GLS_CONTEXT_FLAG_EXERCISE 0x08 /**< Exercise duration and exercise intensity present */
#define BLE_GLS_CONTEXT_FLAG_MED 0x10 /**< Medication ID and medication present */
#define BLE_GLS_CONTEXT_FLAG_MED_KG 0x00 /**< Medication value units, kilograms */
#define BLE_GLS_CONTEXT_FLAG_MED_L 0x20 /**< Medication value units, liters */
#define BLE_GLS_CONTEXT_FLAG_HBA1C 0x40 /**< Hba1c present */
#define BLE_GLS_CONTEXT_FLAG_EXT 0x80 /**< Extended flags present */
/**@brief Glucose measurement context carbohydrate ID */
#define BLE_GLS_CONTEXT_CARB_BREAKFAST 1 /**< Breakfast */
#define BLE_GLS_CONTEXT_CARB_LUNCH 2 /**< Lunch */
#define BLE_GLS_CONTEXT_CARB_DINNER 3 /**< Dinner */
#define BLE_GLS_CONTEXT_CARB_SNACK 4 /**< Snack */
#define BLE_GLS_CONTEXT_CARB_DRINK 5 /**< Drink */
#define BLE_GLS_CONTEXT_CARB_SUPPER 6 /**< Supper */
#define BLE_GLS_CONTEXT_CARB_BRUNCH 7 /**< Brunch */
/**@brief Glucose measurement context meal */
#define BLE_GLS_CONTEXT_MEAL_PREPRANDIAL 1 /**< Preprandial (before meal) */
#define BLE_GLS_CONTEXT_MEAL_POSTPRANDIAL 2 /**< Postprandial (after meal) */
#define BLE_GLS_CONTEXT_MEAL_FASTING 3 /**< Fasting */
#define BLE_GLS_CONTEXT_MEAL_CASUAL 4 /**< Casual (snacks, drinks, etc.) */
#define BLE_GLS_CONTEXT_MEAL_BEDTIME 5 /**< Bedtime */
/**@brief Glucose measurement context tester */
#define BLE_GLS_CONTEXT_TESTER_SELF 1 /**< Self */
#define BLE_GLS_CONTEXT_TESTER_PRO 2 /**< Health care professional */
#define BLE_GLS_CONTEXT_TESTER_LAB 3 /**< Lab test */
#define BLE_GLS_CONTEXT_TESTER_NOT_AVAIL 15 /**< Tester value not available */
/**@brief Glucose measurement context health */
#define BLE_GLS_CONTEXT_HEALTH_MINOR 1 /**< Minor health issues */
#define BLE_GLS_CONTEXT_HEALTH_MAJOR 2 /**< Major health issues */
#define BLE_GLS_CONTEXT_HEALTH_MENSES 3 /**< During menses */
#define BLE_GLS_CONTEXT_HEALTH_STRESS 4 /**< Under stress */
#define BLE_GLS_CONTEXT_HEALTH_NONE 5 /**< No health issues */
#define BLE_GLS_CONTEXT_HEALTH_NOT_AVAIL 15 /**< Health value not available */
/**@brief Glucose measurement context medication ID */
#define BLE_GLS_CONTEXT_MED_RAPID 1 /**< Rapid acting insulin */
#define BLE_GLS_CONTEXT_MED_SHORT 2 /**< Short acting insulin */
#define BLE_GLS_CONTEXT_MED_INTERMED 3 /**< Intermediate acting insulin */
#define BLE_GLS_CONTEXT_MED_LONG 4 /**< Long acting insulin */
#define BLE_GLS_CONTEXT_MED_PREMIX 5 /**< Pre-mixed insulin */
/**@brief SFLOAT format (IEEE-11073 16-bit FLOAT, meaning 4 bits for exponent (base 10) and 12 bits mantissa) */
typedef struct
{
int8_t exponent; /**< Base 10 exponent, should be using only 4 bits */
int16_t mantissa; /**< Mantissa, should be using only 12 bits */
} sfloat_t;
/**@brief Glucose Service event type. */
typedef enum
{
BLE_GLS_EVT_NOTIFICATION_ENABLED, /**< Glucose value notification enabled event. */
BLE_GLS_EVT_NOTIFICATION_DISABLED /**< Glucose value notification disabled event. */
} ble_gls_evt_type_t;
/**@brief Glucose Service event. */
typedef struct
{
ble_gls_evt_type_t evt_type; /**< Type of event. */
} ble_gls_evt_t;
// Forward declaration of the ble_gls_t type.
typedef struct ble_gls_s ble_gls_t;
/**@brief Glucose Service event handler type. */
typedef void (*ble_gls_evt_handler_t) (ble_gls_t * p_gls, ble_gls_evt_t * p_evt);
/**@brief Glucose Measurement structure. This contains glucose measurement value. */
typedef struct
{
uint8_t flags; /**< Flags */
uint16_t sequence_number; /**< Sequence number */
ble_date_time_t base_time; /**< Time stamp */
int16_t time_offset; /**< Time offset */
sfloat_t glucose_concentration; /**< Glucose concentration */
uint8_t type; /**< Type */
uint8_t sample_location; /**< Sample location */
uint16_t sensor_status_annunciation; /**< Sensor status annunciation */
} ble_gls_meas_t;
/**@brief Glucose measurement context structure */
typedef struct
{
uint8_t flags; /**< Flags */
uint8_t extended_flags; /**< Extended Flags */
uint8_t carbohydrate_id; /**< Carbohydrate ID */
sfloat_t carbohydrate; /**< Carbohydrate */
uint8_t meal; /**< Meal */
uint8_t tester_and_health; /**< Tester and health */
uint16_t exercise_duration; /**< Exercise Duration */
uint8_t exercise_intensity; /**< Exercise Intensity */
uint8_t medication_id; /**< Medication ID */
sfloat_t medication; /**< Medication */
uint16_t hba1c; /**< HbA1c */
} ble_gls_meas_context_t;
/**@brief Glucose measurement record */
typedef struct
{
ble_gls_meas_t meas; /**< Glucose measurement */
ble_gls_meas_context_t context; /**< Glucose measurement context */
} ble_gls_rec_t;
/**@brief Glucose Service init structure. This contains all options and data needed for
* initialization of the service. */
typedef struct
{
ble_gls_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Glucose Service. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
uint16_t feature; /**< Glucose Feature value indicating supported features. */
bool is_context_supported; /**< Determines if optional Glucose Measurement Context is to be supported. */
} ble_gls_init_t;
/**@brief Glucose Service structure. This contains various status information for the service. */
struct ble_gls_s
{
ble_gls_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Glucose Service. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
uint16_t service_handle; /**< Handle of Glucose Service (as provided by the BLE stack). */
ble_gatts_char_handles_t glm_handles; /**< Handles related to the Glucose Measurement characteristic. */
ble_gatts_char_handles_t glm_context_handles; /**< Handles related to the Glucose Measurement Context characteristic. */
ble_gatts_char_handles_t glf_handles; /**< Handles related to the Glucose Feature characteristic. */
ble_gatts_char_handles_t racp_handles; /**< Handles related to the Record Access Control Point characteristic. */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
uint16_t feature;
bool is_context_supported;
};
/**@brief Function for initializing the Glucose Service.
*
* @details This call allows the application to initialize the Glucose Service.
*
* @param[out] p_gls Glucose Service structure. This structure will have to be supplied by
* the application. It will be initialized by this function, and will later
* be used to identify this particular service instance.
* @param[in] p_gls_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
*/
uint32_t ble_gls_init(ble_gls_t * p_gls, const ble_gls_init_t * p_gls_init);
/**@brief Function for handling the Application's BLE Stack events.
*
* @details Handles all events from the BLE stack of interest to the Glucose Service.
*
* @param[in] p_gls Glucose Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_gls_on_ble_evt(ble_gls_t * p_gls, ble_evt_t * p_ble_evt);
/**@brief Function for reporting a new glucose measurement to the glucose service module.
*
* @details The application calls this function after having performed a new glucose measurement.
* The new measurement is recorded in the RACP database.
*
* @param[in] p_gls Glucose Service structure.
* @param[in] p_rec Pointer to glucose record (measurement plus context).
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
uint32_t ble_gls_glucose_new_meas(ble_gls_t * p_gls, ble_gls_rec_t * p_rec);
#endif // BLE_GLS_H__
/** @} */

View File

@ -1,112 +0,0 @@
/* 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 "ble_gls_db.h"
typedef struct
{
bool in_use_flag;
ble_gls_rec_t record;
} database_entry_t;
static database_entry_t m_database[BLE_GLS_DB_MAX_RECORDS];
static uint8_t m_database_crossref[BLE_GLS_DB_MAX_RECORDS];
static uint16_t m_num_records;
uint32_t ble_gls_db_init(void)
{
int i;
for (i = 0; i < BLE_GLS_DB_MAX_RECORDS; i++)
{
m_database[i].in_use_flag = false;
m_database_crossref[i] = 0xFF;
}
m_num_records = 0;
return NRF_SUCCESS;
}
uint16_t ble_gls_db_num_records_get(void)
{
return m_num_records;
}
uint32_t ble_gls_db_record_get(uint8_t rec_ndx, ble_gls_rec_t * p_rec)
{
if (rec_ndx >= m_num_records)
{
return NRF_ERROR_INVALID_PARAM;
}
// copy record to the specified memory
*p_rec = m_database[m_database_crossref[rec_ndx]].record;
return NRF_SUCCESS;
}
uint32_t ble_gls_db_record_add(ble_gls_rec_t * p_rec)
{
int i;
if (m_num_records == BLE_GLS_DB_MAX_RECORDS)
{
return NRF_ERROR_NO_MEM;
}
// find next available database entry
for (i = 0; i < BLE_GLS_DB_MAX_RECORDS; i++)
{
if (!m_database[i].in_use_flag)
{
m_database[i].in_use_flag = true;
m_database[i].record = *p_rec;
m_database_crossref[m_num_records] = i;
m_num_records++;
return NRF_SUCCESS;
}
}
return NRF_ERROR_NO_MEM;
}
uint32_t ble_gls_db_record_delete(uint8_t rec_ndx)
{
int i;
if (rec_ndx >= m_num_records)
{
return NRF_ERROR_NOT_FOUND;
}
// free entry
m_database[m_database_crossref[rec_ndx]].in_use_flag = false;
// decrease number of records
m_num_records--;
// remove cross reference index
for (i = rec_ndx; i < m_num_records; i++)
{
m_database_crossref[i] = m_database_crossref[i + 1];
}
return NRF_SUCCESS;
}

View File

@ -1,84 +0,0 @@
/* 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.
*/
/** @file
*
* @defgroup ble_sdk_srv_gls_db Glucose Database Service
* @{
* @ingroup ble_sdk_srv
* @brief Glucose Service module.
*
* @details This module implements at database of stored glucose measurement values.
*
* @note Attention!
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
* qualification listings, These APIs must not be modified. However, the corresponding
* functions' implementations can be modified.
*/
#ifndef BLE_GLS_DB_H__
#define BLE_GLS_DB_H__
#include <stdint.h>
#include "ble_gls.h"
#define BLE_GLS_DB_MAX_RECORDS 20
/**@brief Function for initializing the glucose record database.
*
* @details This call initializes the database holding glucose records.
*
* @return NRF_SUCCESS on success.
*/
uint32_t ble_gls_db_init(void);
/**@brief Function for getting the number of records in the database.
*
* @details This call returns the number of records in the database.
*
* @return Number of records in the database.
*/
uint16_t ble_gls_db_num_records_get(void);
/**@brief Function for getting a record from the database.
*
* @details This call returns a specified record from the database.
*
* @param[in] record_num Index of the record to retrieve.
* @param[out] p_rec Pointer to record structure where retrieved record is copied to.
*
* @return NRF_SUCCESS on success.
*/
uint32_t ble_gls_db_record_get(uint8_t record_num, ble_gls_rec_t * p_rec);
/**@brief Function for adding a record at the end of the database.
*
* @details This call adds a record as the last record in the database.
*
* @param[in] p_rec Pointer to record to add to database.
*
* @return NRF_SUCCESS on success.
*/
uint32_t ble_gls_db_record_add(ble_gls_rec_t * p_rec);
/**@brief Function for deleting a database entry.
*
* @details This call deletes an record from the database.
*
* @param[in] record_num Index of record to delete.
*
* @return NRF_SUCCESS on success.
*/
uint32_t ble_gls_db_record_delete(uint8_t record_num);
#endif // BLE_GLS_DB_H__
/** @} */

View File

@ -1,314 +0,0 @@
/* 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_hids Human Interface Device Service
* @{
* @ingroup ble_sdk_srv
* @brief Human Interface Device Service module.
*
* @details This module implements the Human Interface Device Service with the corresponding set of
* characteristics. During initialization it adds the Human Interface Device Service and
* a set of characteristics as per the Human Interface Device Service specification and
* the user requirements to the BLE stack database.
*
* If enabled, notification of Input Report characteristics is performed when the
* application calls the corresponding ble_hids_xx_input_report_send() function.
*
* If an event handler is supplied by the application, the Human Interface Device Service
* will generate Human Interface Device Service events to the application.
*
* @note The application must propagate BLE stack events to the Human Interface Device Service
* module by calling ble_hids_on_ble_evt() from the @ref softdevice_handler callback.
*
* @note Attention!
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_HIDS_H__
#define BLE_HIDS_H__
#include <stdint.h>
#include <stdbool.h>
#include "ble.h"
#include "ble_srv_common.h"
/** @name Report Type values
* @anchor BLE_HIDS_REPORT_TYPE @{
*/
// Report Type values
#define BLE_HIDS_REP_TYPE_INPUT 1
#define BLE_HIDS_REP_TYPE_OUTPUT 2
#define BLE_HIDS_REP_TYPE_FEATURE 3
/** @} */
// Maximum number of the various Report Types
#define BLE_HIDS_MAX_INPUT_REP 10
#define BLE_HIDS_MAX_OUTPUT_REP 10
#define BLE_HIDS_MAX_FEATURE_REP 10
// Information Flags
#define HID_INFO_FLAG_REMOTE_WAKE_MSK 0x01
#define HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK 0x02
/**@brief HID Service characteristic id. */
typedef struct
{
uint16_t uuid; /**< UUID of characteristic. */
uint8_t rep_type; /**< Type of report (only used for BLE_UUID_REPORT_CHAR, see @ref BLE_HIDS_REPORT_TYPE). */
uint8_t rep_index; /**< Index of the characteristic (only used for BLE_UUID_REPORT_CHAR). */
} ble_hids_char_id_t;
/**@brief HID Service event type. */
typedef enum
{
BLE_HIDS_EVT_HOST_SUSP, /**< Suspend command received. */
BLE_HIDS_EVT_HOST_EXIT_SUSP, /**< Exit suspend command received. */
BLE_HIDS_EVT_NOTIF_ENABLED, /**< Notification enabled event. */
BLE_HIDS_EVT_NOTIF_DISABLED, /**< Notification disabled event. */
BLE_HIDS_EVT_REP_CHAR_WRITE, /**< A new value has been written to an Report characteristic. */
BLE_HIDS_EVT_BOOT_MODE_ENTERED, /**< Boot mode entered. */
BLE_HIDS_EVT_REPORT_MODE_ENTERED, /**< Report mode entered. */
BLE_HIDS_EVT_REPORT_READ /**< Read with response */
} ble_hids_evt_type_t;
/**@brief HID Service event. */
typedef struct
{
ble_hids_evt_type_t evt_type; /**< Type of event. */
union
{
struct
{
ble_hids_char_id_t char_id; /**< Id of characteristic for which notification has been started. */
} notification;
struct
{
ble_hids_char_id_t char_id; /**< Id of characteristic having been written. */
uint16_t offset; /**< Offset for the write operation. */
uint16_t len; /**< Length of the incoming data. */
uint8_t* data; /**< Incoming data, variable length */
} char_write;
struct
{
ble_hids_char_id_t char_id; /**< Id of characteristic being read. */
} char_auth_read;
} params;
ble_evt_t * p_ble_evt; /**< corresponding received ble event, NULL if not relevant */
} ble_hids_evt_t;
// Forward declaration of the ble_hids_t type.
typedef struct ble_hids_s ble_hids_t;
/**@brief HID Service event handler type. */
typedef void (*ble_hids_evt_handler_t) (ble_hids_t * p_hids, ble_hids_evt_t * p_evt);
/**@brief HID Information characteristic value. */
typedef struct
{
uint16_t bcd_hid; /**< 16-bit unsigned integer representing version number of base USB HID Specification implemented by HID Device */
uint8_t b_country_code; /**< Identifies which country the hardware is localized for. Most hardware is not localized and thus this value would be zero (0). */
uint8_t flags; /**< See http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.hid_information.xml */
ble_srv_security_mode_t security_mode; /**< Security mode for the HID Information characteristic. */
} ble_hids_hid_information_t;
/**@brief HID Service Input Report characteristic init structure. This contains all options and
* data needed for initialization of one Input Report characteristic. */
typedef struct
{
uint16_t max_len; /**< Maximum length of characteristic value. */
ble_srv_report_ref_t rep_ref; /**< Value of the Report Reference descriptor. */
ble_srv_cccd_security_mode_t security_mode; /**< Security mode for the HID Input Report characteristic, including cccd. */
uint8_t read_resp : 1; /**< Should application generate a response to read requests. */
} ble_hids_inp_rep_init_t;
/**@brief HID Service Output Report characteristic init structure. This contains all options and
* data needed for initialization of one Output Report characteristic. */
typedef struct
{
uint16_t max_len; /**< Maximum length of characteristic value. */
ble_srv_report_ref_t rep_ref; /**< Value of the Report Reference descriptor. */
ble_srv_cccd_security_mode_t security_mode; /**< Security mode for the HID Output Report characteristic, including cccd. */
uint8_t read_resp : 1; /**< Should application generate a response to read requests. */
} ble_hids_outp_rep_init_t;
/**@brief HID Service Feature Report characteristic init structure. This contains all options and
* data needed for initialization of one Feature Report characteristic. */
typedef struct
{
uint16_t max_len; /**< Maximum length of characteristic value. */
ble_srv_report_ref_t rep_ref; /**< Value of the Report Reference descriptor. */
ble_srv_cccd_security_mode_t security_mode; /**< Security mode for the HID Service Feature Report characteristic, including cccd. */
uint8_t read_resp : 1; /**< Should application generate a response to read requests. */
} ble_hids_feature_rep_init_t;
/**@brief HID Service Report Map characteristic init structure. This contains all options and data
* needed for initialization of the Report Map characteristic. */
typedef struct
{
uint8_t * p_data; /**< Report map data. */
uint16_t data_len; /**< Length of report map data. */
uint8_t ext_rep_ref_num; /**< Number of Optional External Report Reference descriptors. */
ble_uuid_t * p_ext_rep_ref; /**< Optional External Report Reference descriptor (will be added if != NULL). */
ble_srv_security_mode_t security_mode; /**< Security mode for the HID Service Report Map characteristic. */
} ble_hids_rep_map_init_t;
/**@brief HID Report characteristic structure. */
typedef struct
{
ble_gatts_char_handles_t char_handles; /**< Handles related to the Report characteristic. */
uint16_t ref_handle; /**< Handle of the Report Reference descriptor. */
} ble_hids_rep_char_t;
/**@brief HID Service init structure. This contains all options and data needed for initialization
* of the service. */
typedef struct
{
ble_hids_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the HID Service. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
bool is_kb; /**< TRUE if device is operating as a keyboard, FALSE if it is not. */
bool is_mouse; /**< TRUE if device is operating as a mouse, FALSE if it is not. */
uint8_t inp_rep_count; /**< Number of Input Report characteristics. */
ble_hids_inp_rep_init_t * p_inp_rep_array; /**< Information about the Input Report characteristics. */
uint8_t outp_rep_count; /**< Number of Output Report characteristics. */
ble_hids_outp_rep_init_t * p_outp_rep_array; /**< Information about the Output Report characteristics. */
uint8_t feature_rep_count; /**< Number of Feature Report characteristics. */
ble_hids_feature_rep_init_t * p_feature_rep_array; /**< Information about the Feature Report characteristics. */
ble_hids_rep_map_init_t rep_map; /**< Information nedeed for initialization of the Report Map characteristic. */
ble_hids_hid_information_t hid_information; /**< Value of the HID Information characteristic. */
uint8_t included_services_count; /**< Number of services to include in HID service. */
uint16_t * p_included_services_array; /**< Array of services to include in HID service. */
ble_srv_security_mode_t security_mode_protocol; /**< Security settings for HID service protocol attribute */
ble_srv_security_mode_t security_mode_ctrl_point; /**< Security settings for HID service Control Point attribute */
ble_srv_cccd_security_mode_t security_mode_boot_mouse_inp_rep; /**< Security settings for HID service Mouse input report attribute */
ble_srv_cccd_security_mode_t security_mode_boot_kb_inp_rep; /**< Security settings for HID service Keyboard input report attribute */
ble_srv_security_mode_t security_mode_boot_kb_outp_rep; /**< Security settings for HID service Keyboard output report attribute */
} ble_hids_init_t;
/**@brief HID Service structure. This contains various status information for the service. */
struct ble_hids_s
{
ble_hids_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the HID Service. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
uint16_t service_handle; /**< Handle of HID Service (as provided by the BLE stack). */
ble_gatts_char_handles_t protocol_mode_handles; /**< Handles related to the Protocol Mode characteristic (will only be created if ble_hids_init_t.is_kb or ble_hids_init_t.is_mouse is set). */
uint8_t inp_rep_count; /**< Number of Input Report characteristics. */
ble_hids_rep_char_t inp_rep_array[BLE_HIDS_MAX_INPUT_REP]; /**< Information about the Input Report characteristics. */
uint8_t outp_rep_count; /**< Number of Output Report characteristics. */
ble_hids_rep_char_t outp_rep_array[BLE_HIDS_MAX_OUTPUT_REP]; /**< Information about the Output Report characteristics. */
uint8_t feature_rep_count; /**< Number of Feature Report characteristics. */
ble_hids_rep_char_t feature_rep_array[BLE_HIDS_MAX_FEATURE_REP]; /**< Information about the Feature Report characteristics. */
ble_gatts_char_handles_t rep_map_handles; /**< Handles related to the Report Map characteristic. */
uint16_t rep_map_ext_rep_ref_handle; /**< Handle of the Report Map External Report Reference descriptor. */
ble_gatts_char_handles_t boot_kb_inp_rep_handles; /**< Handles related to the Boot Keyboard Input Report characteristic (will only be created if ble_hids_init_t.is_kb is set). */
ble_gatts_char_handles_t boot_kb_outp_rep_handles; /**< Handles related to the Boot Keyboard Output Report characteristic (will only be created if ble_hids_init_t.is_kb is set). */
ble_gatts_char_handles_t boot_mouse_inp_rep_handles; /**< Handles related to the Boot Mouse Input Report characteristic (will only be created if ble_hids_init_t.is_mouse is set). */
ble_gatts_char_handles_t hid_information_handles; /**< Handles related to the Report Map characteristic. */
ble_gatts_char_handles_t hid_control_point_handles; /**< Handles related to the Report Map characteristic. */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
};
/**@brief Function for initializing the HID Service.
*
* @param[out] p_hids HID Service structure. This structure will have to be supplied by the
* application. It will be initialized by this function, and will later be
* used to identify this particular service instance.
* @param[in] p_hids_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
*/
uint32_t ble_hids_init(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init);
/**@brief Function for handling the Application's BLE Stack events.
*
* @details Handles all events from the BLE stack of interest to the HID Service.
*
* @param[in] p_hids HID Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_hids_on_ble_evt(ble_hids_t * p_hids, ble_evt_t * p_ble_evt);
/**@brief Function for sending Input Report.
*
* @details Sends data on an Input Report characteristic.
*
* @param[in] p_hids HID Service structure.
* @param[in] rep_index Index of the characteristic (corresponding to the index in
* ble_hids_t.inp_rep_array as passed to ble_hids_init()).
* @param[in] len Length of data to be sent.
* @param[in] p_data Pointer to data to be sent.
*
* @return NRF_SUCCESS on successful sending of input report, otherwise an error code.
*/
uint32_t ble_hids_inp_rep_send(ble_hids_t * p_hids,
uint8_t rep_index,
uint16_t len,
uint8_t * p_data);
/**@brief Function for sending Boot Keyboard Input Report.
*
* @details Sends data on an Boot Keyboard Input Report characteristic.
*
* @param[in] p_hids HID Service structure.
* @param[in] len Length of data to be sent.
* @param[in] p_data Pointer to data to be sent.
*
* @return NRF_SUCCESS on successful sending of the report, otherwise an error code.
*/
uint32_t ble_hids_boot_kb_inp_rep_send(ble_hids_t * p_hids,
uint16_t len,
uint8_t * p_data);
/**@brief Function for sending Boot Mouse Input Report.
*
* @details Sends data on an Boot Mouse Input Report characteristic.
*
* @param[in] p_hids HID Service structure.
* @param[in] buttons State of mouse buttons.
* @param[in] x_delta Horizontal movement.
* @param[in] y_delta Vertical movement.
* @param[in] optional_data_len Length of optional part of Boot Mouse Input Report.
* @param[in] p_optional_data Optional part of Boot Mouse Input Report.
*
* @return NRF_SUCCESS on successful sending of the report, otherwise an error code.
*/
uint32_t ble_hids_boot_mouse_inp_rep_send(ble_hids_t * p_hids,
uint8_t buttons,
int8_t x_delta,
int8_t y_delta,
uint16_t optional_data_len,
uint8_t * p_optional_data);
/**@brief Function for getting the current value of Output Report from the stack.
*
* @details Fetches the current value of the output report characteristic from the stack.
*
* @param[in] p_hids HID Service structure.
* @param[in] rep_index Index of the characteristic (corresponding to the index in
* ble_hids_t.outp_rep_array as passed to ble_hids_init()).
* @param[in] len Length of output report needed.
* @param[in] offset Offset in bytes to read from.
* @param[out] p_outp_rep Pointer to the output report.
*
* @return NRF_SUCCESS on successful read of the report, otherwise an error code.
*/
uint32_t ble_hids_outp_rep_get(ble_hids_t * p_hids,
uint8_t rep_index,
uint16_t len,
uint8_t offset,
uint8_t * p_outp_rep);
#endif // BLE_HIDS_H__
/** @} */

View File

@ -1,440 +0,0 @@
/* 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.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#include "ble_hrs.h"
#include <string.h>
#include "nordic_common.h"
#include "ble_l2cap.h"
#include "ble_srv_common.h"
#include "app_util.h"
#define OPCODE_LENGTH 1 /**< Length of opcode inside Heart Rate Measurement packet. */
#define HANDLE_LENGTH 2 /**< Length of handle inside Heart Rate Measurement packet. */
#define MAX_HRM_LEN (BLE_L2CAP_MTU_DEF - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Heart Rate Measurement. */
#define INITIAL_VALUE_HRM 0 /**< Initial Heart Rate Measurement value. */
// Heart Rate Measurement flag bits
#define HRM_FLAG_MASK_HR_VALUE_16BIT (0x01 << 0) /**< Heart Rate Value Format bit. */
#define HRM_FLAG_MASK_SENSOR_CONTACT_DETECTED (0x01 << 1) /**< Sensor Contact Detected bit. */
#define HRM_FLAG_MASK_SENSOR_CONTACT_SUPPORTED (0x01 << 2) /**< Sensor Contact Supported bit. */
#define HRM_FLAG_MASK_EXPENDED_ENERGY_INCLUDED (0x01 << 3) /**< Energy Expended Status bit. Feature Not Supported */
#define HRM_FLAG_MASK_RR_INTERVAL_INCLUDED (0x01 << 4) /**< RR-Interval bit. */
/**@brief Function for handling the Connect event.
*
* @param[in] p_hrs Heart Rate Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_connect(ble_hrs_t * p_hrs, ble_evt_t * p_ble_evt)
{
p_hrs->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}
/**@brief Function for handling the Disconnect event.
*
* @param[in] p_hrs Heart Rate Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_disconnect(ble_hrs_t * p_hrs, ble_evt_t * p_ble_evt)
{
UNUSED_PARAMETER(p_ble_evt);
p_hrs->conn_handle = BLE_CONN_HANDLE_INVALID;
}
/**@brief Function for handling write events to the Heart Rate Measurement characteristic.
*
* @param[in] p_hrs Heart Rate Service structure.
* @param[in] p_evt_write Write event received from the BLE stack.
*/
static void on_hrm_cccd_write(ble_hrs_t * p_hrs, ble_gatts_evt_write_t * p_evt_write)
{
if (p_evt_write->len == 2)
{
// CCCD written, update notification state
if (p_hrs->evt_handler != NULL)
{
ble_hrs_evt_t evt;
if (ble_srv_is_notification_enabled(p_evt_write->data))
{
evt.evt_type = BLE_HRS_EVT_NOTIFICATION_ENABLED;
}
else
{
evt.evt_type = BLE_HRS_EVT_NOTIFICATION_DISABLED;
}
p_hrs->evt_handler(p_hrs, &evt);
}
}
}
/**@brief Function for handling the Write event.
*
* @param[in] p_hrs Heart Rate Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_write(ble_hrs_t * p_hrs, ble_evt_t * p_ble_evt)
{
ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
if (p_evt_write->handle == p_hrs->hrm_handles.cccd_handle)
{
on_hrm_cccd_write(p_hrs, p_evt_write);
}
}
void ble_hrs_on_ble_evt(ble_hrs_t * p_hrs, ble_evt_t * p_ble_evt)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_hrs, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_hrs, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_hrs, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
/**@brief Function for encoding a Heart Rate Measurement.
*
* @param[in] p_hrs Heart Rate Service structure.
* @param[in] heart_rate Measurement to be encoded.
* @param[out] p_encoded_buffer Buffer where the encoded data will be written.
*
* @return Size of encoded data.
*/
static uint8_t hrm_encode(ble_hrs_t * p_hrs, uint16_t heart_rate, uint8_t * p_encoded_buffer)
{
uint8_t flags = 0;
uint8_t len = 1;
int i;
// Set sensor contact related flags
if (p_hrs->is_sensor_contact_supported)
{
flags |= HRM_FLAG_MASK_SENSOR_CONTACT_SUPPORTED;
}
if (p_hrs->is_sensor_contact_detected)
{
flags |= HRM_FLAG_MASK_SENSOR_CONTACT_DETECTED;
}
// Encode heart rate measurement
if (heart_rate > 0xff)
{
flags |= HRM_FLAG_MASK_HR_VALUE_16BIT;
len += uint16_encode(heart_rate, &p_encoded_buffer[len]);
}
else
{
p_encoded_buffer[len++] = (uint8_t)heart_rate;
}
// Encode rr_interval values
if (p_hrs->rr_interval_count > 0)
{
flags |= HRM_FLAG_MASK_RR_INTERVAL_INCLUDED;
}
for (i = 0; i < p_hrs->rr_interval_count; i++)
{
if (len + sizeof(uint16_t) > MAX_HRM_LEN)
{
// Not all stored rr_interval values can fit into the encoded hrm,
// move the remaining values to the start of the buffer.
memmove(&p_hrs->rr_interval[0],
&p_hrs->rr_interval[i],
(p_hrs->rr_interval_count - i) * sizeof(uint16_t));
break;
}
len += uint16_encode(p_hrs->rr_interval[i], &p_encoded_buffer[len]);
}
p_hrs->rr_interval_count -= i;
// Add flags
p_encoded_buffer[0] = flags;
return len;
}
/**@brief Function for adding the Heart Rate Measurement characteristic.
*
* @param[in] p_hrs Heart Rate Service structure.
* @param[in] p_hrs_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t heart_rate_measurement_char_add(ble_hrs_t * p_hrs,
const ble_hrs_init_t * p_hrs_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_md_t cccd_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
uint8_t encoded_initial_hrm[MAX_HRM_LEN];
memset(&cccd_md, 0, sizeof(cccd_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
cccd_md.write_perm = p_hrs_init->hrs_hrm_attr_md.cccd_write_perm;
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.notify = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = &cccd_md;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_HEART_RATE_MEASUREMENT_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
attr_md.read_perm = p_hrs_init->hrs_hrm_attr_md.read_perm;
attr_md.write_perm = p_hrs_init->hrs_hrm_attr_md.write_perm;
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = hrm_encode(p_hrs, INITIAL_VALUE_HRM, encoded_initial_hrm);
attr_char_value.init_offs = 0;
attr_char_value.max_len = MAX_HRM_LEN;
attr_char_value.p_value = encoded_initial_hrm;
return sd_ble_gatts_characteristic_add(p_hrs->service_handle,
&char_md,
&attr_char_value,
&p_hrs->hrm_handles);
}
/**@brief Function for adding the Body Sensor Location characteristic.
*
* @param[in] p_hrs Heart Rate Service structure.
* @param[in] p_hrs_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t body_sensor_location_char_add(ble_hrs_t * p_hrs, const ble_hrs_init_t * p_hrs_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BODY_SENSOR_LOCATION_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
attr_md.read_perm = p_hrs_init->hrs_bsl_attr_md.read_perm;
attr_md.write_perm = p_hrs_init->hrs_bsl_attr_md.write_perm;
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 0;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof (uint8_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = sizeof (uint8_t);
attr_char_value.p_value = p_hrs_init->p_body_sensor_location;
return sd_ble_gatts_characteristic_add(p_hrs->service_handle,
&char_md,
&attr_char_value,
&p_hrs->bsl_handles);
}
uint32_t ble_hrs_init(ble_hrs_t * p_hrs, const ble_hrs_init_t * p_hrs_init)
{
uint32_t err_code;
ble_uuid_t ble_uuid;
// Initialize service structure
p_hrs->evt_handler = p_hrs_init->evt_handler;
p_hrs->is_sensor_contact_supported = p_hrs_init->is_sensor_contact_supported;
p_hrs->conn_handle = BLE_CONN_HANDLE_INVALID;
p_hrs->is_sensor_contact_detected = false;
p_hrs->rr_interval_count = 0;
// Add service
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_HEART_RATE_SERVICE);
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
&ble_uuid,
&p_hrs->service_handle);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add heart rate measurement characteristic
err_code = heart_rate_measurement_char_add(p_hrs, p_hrs_init);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
if (p_hrs_init->p_body_sensor_location != NULL)
{
// Add body sensor location characteristic
err_code = body_sensor_location_char_add(p_hrs, p_hrs_init);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
return NRF_SUCCESS;
}
uint32_t ble_hrs_heart_rate_measurement_send(ble_hrs_t * p_hrs, uint16_t heart_rate)
{
uint32_t err_code;
// Send value if connected and notifying
if (p_hrs->conn_handle != BLE_CONN_HANDLE_INVALID)
{
uint8_t encoded_hrm[MAX_HRM_LEN];
uint16_t len;
uint16_t hvx_len;
ble_gatts_hvx_params_t hvx_params;
len = hrm_encode(p_hrs, heart_rate, encoded_hrm);
hvx_len = len;
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_hrs->hrm_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
hvx_params.offset = 0;
hvx_params.p_len = &hvx_len;
hvx_params.p_data = encoded_hrm;
err_code = sd_ble_gatts_hvx(p_hrs->conn_handle, &hvx_params);
if ((err_code == NRF_SUCCESS) && (hvx_len != len))
{
err_code = NRF_ERROR_DATA_SIZE;
}
}
else
{
err_code = NRF_ERROR_INVALID_STATE;
}
return err_code;
}
void ble_hrs_rr_interval_add(ble_hrs_t * p_hrs, uint16_t rr_interval)
{
if (p_hrs->rr_interval_count == BLE_HRS_MAX_BUFFERED_RR_INTERVALS)
{
// The rr_interval buffer is full, delete the oldest value
memmove(&p_hrs->rr_interval[0],
&p_hrs->rr_interval[1],
(BLE_HRS_MAX_BUFFERED_RR_INTERVALS - 1) * sizeof(uint16_t));
p_hrs->rr_interval_count--;
}
// Add new value
p_hrs->rr_interval[p_hrs->rr_interval_count++] = rr_interval;
}
bool ble_hrs_rr_interval_buffer_is_full(ble_hrs_t * p_hrs)
{
return (p_hrs->rr_interval_count == BLE_HRS_MAX_BUFFERED_RR_INTERVALS);
}
uint32_t ble_hrs_sensor_contact_supported_set(ble_hrs_t * p_hrs, bool is_sensor_contact_supported)
{
// Check if we are connected to peer
if (p_hrs->conn_handle == BLE_CONN_HANDLE_INVALID)
{
p_hrs->is_sensor_contact_supported = is_sensor_contact_supported;
return NRF_SUCCESS;
}
else
{
return NRF_ERROR_INVALID_STATE;
}
}
void ble_hrs_sensor_contact_detected_update(ble_hrs_t * p_hrs, bool is_sensor_contact_detected)
{
p_hrs->is_sensor_contact_detected = is_sensor_contact_detected;
}
uint32_t ble_hrs_body_sensor_location_set(ble_hrs_t * p_hrs, uint8_t body_sensor_location)
{
ble_gatts_value_t gatts_value;
// Initialize value struct.
memset(&gatts_value, 0, sizeof(gatts_value));
gatts_value.len = sizeof(uint8_t);
gatts_value.offset = 0;
gatts_value.p_value = &body_sensor_location;
return sd_ble_gatts_value_set(p_hrs->conn_handle, p_hrs->bsl_handles.value_handle, &gatts_value);
}

View File

@ -1,192 +0,0 @@
/* 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_hrs Heart Rate Service
* @{
* @ingroup ble_sdk_srv
* @brief Heart Rate Service module.
*
* @details This module implements the Heart Rate Service with the Heart Rate Measurement,
* Body Sensor Location and Heart Rate Control Point characteristics.
* During initialization it adds the Heart Rate Service and Heart Rate Measurement
* characteristic to the BLE stack database. Optionally it also adds the
* Body Sensor Location and Heart Rate Control Point characteristics.
*
* If enabled, notification of the Heart Rate Measurement characteristic is performed
* when the application calls ble_hrs_heart_rate_measurement_send().
*
* The Heart Rate Service also provides a set of functions for manipulating the
* various fields in the Heart Rate Measurement characteristic, as well as setting
* the Body Sensor Location characteristic value.
*
* If an event handler is supplied by the application, the Heart Rate Service will
* generate Heart Rate Service events to the application.
*
* @note The application must propagate BLE stack events to the Heart Rate Service module by calling
* ble_hrs_on_ble_evt() from the @ref softdevice_handler callback.
*
* @note Attention!
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_HRS_H__
#define BLE_HRS_H__
#include <stdint.h>
#include <stdbool.h>
#include "ble.h"
#include "ble_srv_common.h"
// Body Sensor Location values
#define BLE_HRS_BODY_SENSOR_LOCATION_OTHER 0
#define BLE_HRS_BODY_SENSOR_LOCATION_CHEST 1
#define BLE_HRS_BODY_SENSOR_LOCATION_WRIST 2
#define BLE_HRS_BODY_SENSOR_LOCATION_FINGER 3
#define BLE_HRS_BODY_SENSOR_LOCATION_HAND 4
#define BLE_HRS_BODY_SENSOR_LOCATION_EAR_LOBE 5
#define BLE_HRS_BODY_SENSOR_LOCATION_FOOT 6
#define BLE_HRS_MAX_BUFFERED_RR_INTERVALS 20 /**< Size of RR Interval buffer inside service. */
/**@brief Heart Rate Service event type. */
typedef enum
{
BLE_HRS_EVT_NOTIFICATION_ENABLED, /**< Heart Rate value notification enabled event. */
BLE_HRS_EVT_NOTIFICATION_DISABLED /**< Heart Rate value notification disabled event. */
} ble_hrs_evt_type_t;
/**@brief Heart Rate Service event. */
typedef struct
{
ble_hrs_evt_type_t evt_type; /**< Type of event. */
} ble_hrs_evt_t;
// Forward declaration of the ble_hrs_t type.
typedef struct ble_hrs_s ble_hrs_t;
/**@brief Heart Rate Service event handler type. */
typedef void (*ble_hrs_evt_handler_t) (ble_hrs_t * p_hrs, ble_hrs_evt_t * p_evt);
/**@brief Heart Rate Service init structure. This contains all options and data needed for
* initialization of the service. */
typedef struct
{
ble_hrs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Heart Rate Service. */
bool is_sensor_contact_supported; /**< Determines if sensor contact detection is to be supported. */
uint8_t * p_body_sensor_location; /**< If not NULL, initial value of the Body Sensor Location characteristic. */
ble_srv_cccd_security_mode_t hrs_hrm_attr_md; /**< Initial security level for heart rate service measurement attribute */
ble_srv_security_mode_t hrs_bsl_attr_md; /**< Initial security level for body sensor location attribute */
} ble_hrs_init_t;
/**@brief Heart Rate Service structure. This contains various status information for the service. */
struct ble_hrs_s
{
ble_hrs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Heart Rate Service. */
bool is_expended_energy_supported; /**< TRUE if Expended Energy measurement is supported. */
bool is_sensor_contact_supported; /**< TRUE if sensor contact detection is supported. */
uint16_t service_handle; /**< Handle of Heart Rate Service (as provided by the BLE stack). */
ble_gatts_char_handles_t hrm_handles; /**< Handles related to the Heart Rate Measurement characteristic. */
ble_gatts_char_handles_t bsl_handles; /**< Handles related to the Body Sensor Location characteristic. */
ble_gatts_char_handles_t hrcp_handles; /**< Handles related to the Heart Rate Control Point characteristic. */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
bool is_sensor_contact_detected; /**< TRUE if sensor contact has been detected. */
uint16_t rr_interval[BLE_HRS_MAX_BUFFERED_RR_INTERVALS]; /**< Set of RR Interval measurements since the last Heart Rate Measurement transmission. */
uint16_t rr_interval_count; /**< Number of RR Interval measurements since the last Heart Rate Measurement transmission. */
};
/**@brief Function for initializing the Heart Rate Service.
*
* @param[out] p_hrs Heart Rate Service structure. This structure will have to be supplied by
* the application. It will be initialized by this function, and will later
* be used to identify this particular service instance.
* @param[in] p_hrs_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
*/
uint32_t ble_hrs_init(ble_hrs_t * p_hrs, const ble_hrs_init_t * p_hrs_init);
/**@brief Function for handling the Application's BLE Stack events.
*
* @details Handles all events from the BLE stack of interest to the Heart Rate Service.
*
* @param[in] p_hrs Heart Rate Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_hrs_on_ble_evt(ble_hrs_t * p_hrs, ble_evt_t * p_ble_evt);
/**@brief Function for sending heart rate measurement if notification has been enabled.
*
* @details The application calls this function after having performed a heart rate measurement.
* If notification has been enabled, the heart rate measurement data is encoded and sent to
* the client.
*
* @param[in] p_hrs Heart Rate Service structure.
* @param[in] heart_rate New heart rate measurement.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
uint32_t ble_hrs_heart_rate_measurement_send(ble_hrs_t * p_hrs, uint16_t heart_rate);
/**@brief Function for adding a RR Interval measurement to the RR Interval buffer.
*
* @details All buffered RR Interval measurements will be included in the next heart rate
* measurement message, up to the maximum number of measurements that will fit into the
* message. If the buffer is full, the oldest measurement in the buffer will be deleted.
*
* @param[in] p_hrs Heart Rate Service structure.
* @param[in] rr_interval New RR Interval measurement (will be buffered until the next
* transmission of Heart Rate Measurement).
*/
void ble_hrs_rr_interval_add(ble_hrs_t * p_hrs, uint16_t rr_interval);
/**@brief Function for checking if RR Interval buffer is full.
*
* @param[in] p_hrs Heart Rate Service structure.
*
* @return true if RR Interval buffer is full, false otherwise.
*/
bool ble_hrs_rr_interval_buffer_is_full(ble_hrs_t * p_hrs);
/**@brief Function for setting the state of the Sensor Contact Supported bit.
*
* @param[in] p_hrs Heart Rate Service structure.
* @param[in] is_sensor_contact_supported New state of the Sensor Contact Supported bit.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
uint32_t ble_hrs_sensor_contact_supported_set(ble_hrs_t * p_hrs, bool is_sensor_contact_supported);
/**@brief Function for setting the state of the Sensor Contact Detected bit.
*
* @param[in] p_hrs Heart Rate Service structure.
* @param[in] is_sensor_contact_detected TRUE if sensor contact is detected, FALSE otherwise.
*/
void ble_hrs_sensor_contact_detected_update(ble_hrs_t * p_hrs, bool is_sensor_contact_detected);
/**@brief Function for setting the Body Sensor Location.
*
* @details Sets a new value of the Body Sensor Location characteristic. The new value will be sent
* to the client the next time the client reads the Body Sensor Location characteristic.
*
* @param[in] p_hrs Heart Rate Service structure.
* @param[in] body_sensor_location New Body Sensor Location.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
uint32_t ble_hrs_body_sensor_location_set(ble_hrs_t * p_hrs, uint8_t body_sensor_location);
#endif // BLE_HRS_H__
/** @} */

View File

@ -1,331 +0,0 @@
/*
* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is confidential property of Nordic Semiconductor. The use,
* copying, transfer or disclosure of such information is prohibited except by express written
* agreement with Nordic Semiconductor.
*
*/
/**@cond To Make Doxygen skip documentation generation for this file.
* @{
*/
#include "ble_hrs_c.h"
#include "ble_db_discovery.h"
#include "ble_types.h"
#include "ble_srv_common.h"
#include "ble_gattc.h"
#include "app_trace.h"
#include "sdk_common.h"
#include "nrf_log.h"
#define LOG NRF_LOG_PRINTF_DEBUG /**< Debug logger macro that will be used in this file to do logging of important information over UART. */
#define HRM_FLAG_MASK_HR_16BIT (0x01 << 0) /**< Bit mask used to extract the type of heart rate value. This is used to find if the received heart rate is a 16 bit value or an 8 bit value. */
#define TX_BUFFER_MASK 0x07 /**< TX Buffer mask, must be a mask of continuous zeroes, followed by continuous 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 BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
#define WRITE_MESSAGE_LENGTH BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
typedef enum
{
READ_REQ, /**< Type identifying that this tx_message is a read request. */
WRITE_REQ /**< Type identifying that this tx_message is a write request. */
} tx_request_t;
/**@brief Structure for writing a message to the peer, i.e. 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 central.
*/
typedef struct
{
uint16_t conn_handle; /**< Connection handle to be used when transmitting this message. */
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 central. */
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. */
/**@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)
{
LOG("[HRS_C]: SD Read/Write API returns Success..\r\n");
m_tx_index++;
m_tx_index &= TX_BUFFER_MASK;
}
else
{
LOG("[HRS_C]: SD Read/Write API returns error. This message sending will be "
"attempted again..\r\n");
}
}
}
/**@brief Function for handling write response events.
*
* @param[in] p_ble_hrs_c Pointer to the Heart Rate Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_write_rsp(ble_hrs_c_t * p_ble_hrs_c, const ble_evt_t * p_ble_evt)
{
// Check if the event if on the link for this instance
if (p_ble_hrs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
{
return;
}
// Check if there is any message to be sent across to the peer and send it.
tx_buffer_process();
}
/**@brief Function for handling Handle Value Notification received from the SoftDevice.
*
* @details This function will uses the Handle Value Notification received from the SoftDevice
* and checks if it is a notification of the heart rate measurement from the peer. If
* it is, this function will decode the heart rate measurement and send it to the
* application.
*
* @param[in] p_ble_hrs_c Pointer to the Heart Rate Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_hvx(ble_hrs_c_t * p_ble_hrs_c, const ble_evt_t * p_ble_evt)
{
// Check if the event is on the link for this instance
if (p_ble_hrs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
{
LOG("[HRS_C]: received HVX on link 0x%x, not associated to this instance, ignore\r\n",
p_ble_evt->evt.gattc_evt.conn_handle);
return;
}
LOG("[HRS_C]: received HVX on handle 0x%x, hrm_handle 0x%x\r\n",
p_ble_evt->evt.gattc_evt.params.hvx.handle,
p_ble_hrs_c->peer_hrs_db.hrm_handle);
// Check if this is a heart rate notification.
if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_hrs_c->peer_hrs_db.hrm_handle)
{
ble_hrs_c_evt_t ble_hrs_c_evt;
uint32_t index = 0;
ble_hrs_c_evt.evt_type = BLE_HRS_C_EVT_HRM_NOTIFICATION;
ble_hrs_c_evt.conn_handle = p_ble_hrs_c->conn_handle;
if (!(p_ble_evt->evt.gattc_evt.params.hvx.data[index++] & HRM_FLAG_MASK_HR_16BIT))
{
// 8 Bit heart rate value received.
ble_hrs_c_evt.params.hrm.hr_value = p_ble_evt->evt.gattc_evt.params.hvx.data[index++]; //lint !e415 suppress Lint Warning 415: Likely access out of bond
}
else
{
// 16 bit heart rate value received.
ble_hrs_c_evt.params.hrm.hr_value =
uint16_decode(&(p_ble_evt->evt.gattc_evt.params.hvx.data[index]));
}
p_ble_hrs_c->evt_handler(p_ble_hrs_c, &ble_hrs_c_evt);
}
}
/**@brief Function for handling Disconnected event received from the SoftDevice.
*
* @details This function check if the disconnect event is happening on the link
* associated with the current instance of the module, if so it will set its
* conn_handle to invalid.
*
* @param[in] p_ble_hrs_c Pointer to the Heart Rate Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_disconnected(ble_hrs_c_t * p_ble_hrs_c, const ble_evt_t * p_ble_evt)
{
if (p_ble_hrs_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
{
p_ble_hrs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle = BLE_GATT_HANDLE_INVALID;
p_ble_hrs_c->peer_hrs_db.hrm_handle = BLE_GATT_HANDLE_INVALID;
}
}
void ble_hrs_on_db_disc_evt(ble_hrs_c_t * p_ble_hrs_c, const ble_db_discovery_evt_t * p_evt)
{
// Check if the Heart Rate Service was discovered.
if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_HEART_RATE_SERVICE &&
p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
{
// Find the CCCD Handle of the Heart Rate Measurement characteristic.
uint32_t i;
ble_hrs_c_evt_t evt;
evt.evt_type = BLE_HRS_C_EVT_DISCOVERY_COMPLETE;
evt.conn_handle = p_evt->conn_handle;
for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid ==
BLE_UUID_HEART_RATE_MEASUREMENT_CHAR)
{
// Found Heart Rate characteristic. Store CCCD handle and break.
evt.params.peer_db.hrm_cccd_handle =
p_evt->params.discovered_db.charateristics[i].cccd_handle;
evt.params.peer_db.hrm_handle =
p_evt->params.discovered_db.charateristics[i].characteristic.handle_value;
break;
}
}
LOG("[HRS_C]: Heart Rate Service discovered at peer.\r\n");
//If the instance has been assigned prior to db_discovery, assign the db_handles
if(p_ble_hrs_c->conn_handle != BLE_CONN_HANDLE_INVALID)
{
if ((p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle == BLE_GATT_HANDLE_INVALID)&&
(p_ble_hrs_c->peer_hrs_db.hrm_handle == BLE_GATT_HANDLE_INVALID))
{
p_ble_hrs_c->peer_hrs_db = evt.params.peer_db;
}
}
p_ble_hrs_c->evt_handler(p_ble_hrs_c, &evt);
}
}
uint32_t ble_hrs_c_init(ble_hrs_c_t * p_ble_hrs_c, ble_hrs_c_init_t * p_ble_hrs_c_init)
{
VERIFY_PARAM_NOT_NULL(p_ble_hrs_c);
VERIFY_PARAM_NOT_NULL(p_ble_hrs_c_init);
ble_uuid_t hrs_uuid;
hrs_uuid.type = BLE_UUID_TYPE_BLE;
hrs_uuid.uuid = BLE_UUID_HEART_RATE_SERVICE;
p_ble_hrs_c->evt_handler = p_ble_hrs_c_init->evt_handler;
p_ble_hrs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle = BLE_GATT_HANDLE_INVALID;
p_ble_hrs_c->peer_hrs_db.hrm_handle = BLE_GATT_HANDLE_INVALID;
return ble_db_discovery_evt_register(&hrs_uuid);
}
void ble_hrs_c_on_ble_evt(ble_hrs_c_t * p_ble_hrs_c, const ble_evt_t * p_ble_evt)
{
if ((p_ble_hrs_c == NULL) || (p_ble_evt == NULL))
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_GATTC_EVT_HVX:
on_hvx(p_ble_hrs_c, p_ble_evt);
break;
case BLE_GATTC_EVT_WRITE_RSP:
on_write_rsp(p_ble_hrs_c, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnected(p_ble_hrs_c, p_ble_evt);
break;
default:
break;
}
}
/**@brief Function for creating a message for writing to the CCCD.
*/
static uint32_t cccd_configure(uint16_t conn_handle, uint16_t handle_cccd, bool enable)
{
LOG("[HRS_C]: Configuring CCCD. CCCD Handle = %d, Connection Handle = %d\r\n",
handle_cccd,conn_handle);
tx_message_t * p_msg;
uint16_t cccd_val = enable ? BLE_GATT_HVX_NOTIFICATION : 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 = 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_16(cccd_val);
p_msg->req.write_req.gattc_value[1] = MSB_16(cccd_val);
p_msg->conn_handle = conn_handle;
p_msg->type = WRITE_REQ;
tx_buffer_process();
return NRF_SUCCESS;
}
uint32_t ble_hrs_c_hrm_notif_enable(ble_hrs_c_t * p_ble_hrs_c)
{
VERIFY_PARAM_NOT_NULL(p_ble_hrs_c);
return cccd_configure(p_ble_hrs_c->conn_handle,
p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle,
true);
}
uint32_t ble_hrs_c_handles_assign(ble_hrs_c_t * p_ble_hrs_c,
uint16_t conn_handle,
const hrs_db_t * p_peer_hrs_handles)
{
VERIFY_PARAM_NOT_NULL(p_ble_hrs_c);
p_ble_hrs_c->conn_handle = conn_handle;
if (p_peer_hrs_handles != NULL)
{
p_ble_hrs_c->peer_hrs_db = *p_peer_hrs_handles;
}
return NRF_SUCCESS;
}
/** @}
* @endcond
*/

View File

@ -1,215 +0,0 @@
/*
* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is confidential property of Nordic Semiconductor. The use,
* copying, transfer or disclosure of such information is prohibited except by express written
* agreement with Nordic Semiconductor.
*
*/
/**@file
*
* @defgroup ble_sdk_srv_hrs_c Heart Rate Service Client
* @{
* @ingroup ble_sdk_srv
* @brief Heart Rate Service Client module.
*
* @details This module contains the APIs and types exposed by the Heart Rate Service Client
* module. These APIs and types can be used by the application to perform discovery of
* Heart Rate Service at the peer and interact with it.
*
* @warning Currently this module only has support for Heart Rate Measurement characteristic. This
* means that it will be able to enable notification of the characteristic at the peer and
* be able to receive Heart Rate Measurement notifications from the peer. It does not
* support the Body Sensor Location and the Heart Rate Control Point characteristics.
* When a Heart Rate Measurement is received, this module will decode only the
* Heart Rate Measurement Value (both 8 bit and 16 bit) field from it and provide it to
* the application.
*
* @note The application must propagate BLE stack events to this module by calling
* ble_hrs_c_on_ble_evt().
*
*/
#ifndef BLE_HRS_C_H__
#define BLE_HRS_C_H__
#include <stdint.h>
#include "ble.h"
#include "ble_db_discovery.h"
/**
* @defgroup hrs_c_enums Enumerations
* @{
*/
/**@brief HRS Client event type. */
typedef enum
{
BLE_HRS_C_EVT_DISCOVERY_COMPLETE = 1, /**< Event indicating that the Heart Rate Service has been discovered at the peer. */
BLE_HRS_C_EVT_HRM_NOTIFICATION /**< Event indicating that a notification of the Heart Rate Measurement characteristic has been received from the peer. */
} ble_hrs_c_evt_type_t;
/** @} */
/**
* @defgroup hrs_c_structs Structures
* @{
*/
/**@brief Structure containing the heart rate measurement received from the peer. */
typedef struct
{
uint16_t hr_value; /**< Heart Rate Value. */
} ble_hrm_t;
/**@brief Structure containing the handles related to the Heart Rate Service found on the peer. */
typedef struct
{
uint16_t hrm_cccd_handle; /**< Handle of the CCCD of the Heart Rate Measurement characteristic. */
uint16_t hrm_handle; /**< Handle of the Heart Rate Measurement characteristic as provided by the SoftDevice. */
} hrs_db_t;
/**@brief Heart Rate Event structure. */
typedef struct
{
ble_hrs_c_evt_type_t evt_type; /**< Type of the event. */
uint16_t conn_handle; /**< Connection handle on which the Heart Rate service was discovered on the peer device..*/
union
{
hrs_db_t peer_db; /**< Heart Rate related handles found on the peer device.. This will be filled if the evt_type is @ref BLE_HRS_C_EVT_DISCOVERY_COMPLETE.*/
ble_hrm_t hrm; /**< Heart rate measurement received. This will be filled if the evt_type is @ref BLE_HRS_C_EVT_HRM_NOTIFICATION. */
} params;
} ble_hrs_c_evt_t;
/** @} */
/**
* @defgroup hrs_c_types Types
* @{
*/
// Forward declaration of the ble_bas_t type.
typedef struct ble_hrs_c_s ble_hrs_c_t;
/**@brief Event handler type.
*
* @details This is the type of the event handler that should be provided by the application
* of this module in order to receive events.
*/
typedef void (* ble_hrs_c_evt_handler_t) (ble_hrs_c_t * p_ble_hrs_c, ble_hrs_c_evt_t * p_evt);
/** @} */
/**
* @addtogroup hrs_c_structs
* @{
*/
/**@brief Heart Rate Client structure.
*/
struct ble_hrs_c_s
{
uint16_t conn_handle; /**< Connection handle as provided by the SoftDevice. */
hrs_db_t peer_hrs_db; /**< Handles related to HRS on the peer*/
ble_hrs_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the heart rate service. */
};
/**@brief Heart Rate Client initialization structure.
*/
typedef struct
{
ble_hrs_c_evt_handler_t evt_handler; /**< Event handler to be called by the Heart Rate Client module whenever there is an event related to the Heart Rate Service. */
} ble_hrs_c_init_t;
/** @} */
/**
* @defgroup hrs_c_functions Functions
* @{
*/
/**@brief Function for initializing the heart rate client module.
*
* @details This function will register with the DB Discovery module. There it
* registers for the Heart Rate Service. Doing so will make the DB Discovery
* module look for the presence of a Heart Rate Service instance at the peer when a
* discovery is started.
*
* @param[in] p_ble_hrs_c Pointer to the heart rate client structure.
* @param[in] p_ble_hrs_c_init Pointer to the heart rate initialization structure containing the
* initialization information.
*
* @retval NRF_SUCCESS On successful initialization. Otherwise an error code. This function
* propagates the error code returned by the Database Discovery module API
* @ref ble_db_discovery_evt_register.
*/
uint32_t ble_hrs_c_init(ble_hrs_c_t * p_ble_hrs_c, ble_hrs_c_init_t * p_ble_hrs_c_init);
/**@brief Function for handling BLE events from the SoftDevice.
*
* @details This function will handle the BLE events received from the SoftDevice. If a BLE
* event is relevant to the Heart Rate Client module, then it uses it to update
* interval variables and, if necessary, send events to the application.
*
* @param[in] p_ble_hrs_c Pointer to the heart rate client structure.
* @param[in] p_ble_evt Pointer to the BLE event.
*/
void ble_hrs_c_on_ble_evt(ble_hrs_c_t * p_ble_hrs_c, const ble_evt_t * p_ble_evt);
/**@brief Function for requesting the peer to start sending notification of Heart Rate
* Measurement.
*
* @details This function will enable to notification of the Heart Rate Measurement at the peer
* by writing to the CCCD of the Heart Rate Measurement Characteristic.
*
* @param p_ble_hrs_c Pointer to the heart rate client structure.
*
* @retval NRF_SUCCESS If the SoftDevice has been requested to write to the CCCD of the peer.
* Otherwise, an error code. This function propagates the error code returned
* by the SoftDevice API @ref sd_ble_gattc_write.
*/
uint32_t ble_hrs_c_hrm_notif_enable(ble_hrs_c_t * p_ble_hrs_c);
/**@brief Function for handling events from the database discovery module.
*
* @details Call this function when getting a callback event from the DB discovery modue.
* This function will handle an event from the database discovery module, and determine
* if it relates to the discovery of heart rate service at the peer. If so, it will
* call the application's event handler indicating that the heart rate 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_ble_hrs_c Pointer to the heart rate client structure instance to associate.
* @param[in] p_evt Pointer to the event received from the database discovery module.
*
*/
void ble_hrs_on_db_disc_evt(ble_hrs_c_t * p_ble_hrs_c, const ble_db_discovery_evt_t * p_evt);
/**@brief Function for assigning a handles to a this instance of hrs_c.
*
* @details Call this function when a link has been established with a peer to
* associate this link to this instance of the module. This makes it
* possible to handle several link and associate each link to a particular
* instance of this module.The connection handle and attribute handles will be
* provided from the discovery event @ref BLE_HRS_C_EVT_DISCOVERY_COMPLETE.
*
* @param[in] p_ble_hrs_c Pointer to the heart rate client structure instance to associate.
* @param[in] conn_handle Connection handle to associated with the given Heart Rate Client Instance.
* @param[in] p_peer_hrs_handles Attribute handles for the HRS server you want this HRS_C client to
* interact with.
*/
uint32_t ble_hrs_c_handles_assign(ble_hrs_c_t * p_ble_hrs_c,
uint16_t conn_handle,
const hrs_db_t * p_peer_hrs_handles);
/** @} */ // End tag for Function group.
#endif // BLE_HRS_C_H__
/** @} */ // End tag for the file.

View File

@ -1,428 +0,0 @@
/* 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.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#include "ble_hts.h"
#include <string.h>
#include "nordic_common.h"
#include "ble_l2cap.h"
#include "ble_srv_common.h"
#include "app_util.h"
#define OPCODE_LENGTH 1 /**< Length of opcode inside Health Thermometer Measurement packet. */
#define HANDLE_LENGTH 2 /**< Length of handle inside Health Thermometer Measurement packet. */
#define MAX_HTM_LEN (BLE_L2CAP_MTU_DEF - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Health Thermometer Measurement. */
// Health Thermometer Measurement flag bits
#define HTS_MEAS_FLAG_TEMP_UNITS_BIT (0x01 << 0) /**< Temperature Units flag. */
#define HTS_MEAS_FLAG_TIME_STAMP_BIT (0x01 << 1) /**< Time Stamp flag. */
#define HTS_MEAS_FLAG_TEMP_TYPE_BIT (0x01 << 2) /**< Temperature Type flag. */
/**@brief Function for handling the Connect event.
*
* @param[in] p_hts Health Thermometer Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_connect(ble_hts_t * p_hts, ble_evt_t * p_ble_evt)
{
p_hts->conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
}
/**@brief Function for handling the Disconnect event.
*
* @param[in] p_hts Health Thermometer Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_disconnect(ble_hts_t * p_hts, ble_evt_t * p_ble_evt)
{
UNUSED_PARAMETER(p_ble_evt);
p_hts->conn_handle = BLE_CONN_HANDLE_INVALID;
}
/**@brief Function for handling write events to the Blood Pressure Measurement characteristic.
*
* @param[in] p_hts Health Thermometer Service structure.
* @param[in] p_evt_write Write event received from the BLE stack.
*/
static void on_cccd_write(ble_hts_t * p_hts, ble_gatts_evt_write_t * p_evt_write)
{
if (p_evt_write->len == 2)
{
// CCCD written, update indication state
if (p_hts->evt_handler != NULL)
{
ble_hts_evt_t evt;
if (ble_srv_is_indication_enabled(p_evt_write->data))
{
evt.evt_type = BLE_HTS_EVT_INDICATION_ENABLED;
}
else
{
evt.evt_type = BLE_HTS_EVT_INDICATION_DISABLED;
}
p_hts->evt_handler(p_hts, &evt);
}
}
}
/**@brief Function for handling the Write event.
*
* @param[in] p_hts Health Thermometer Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_write(ble_hts_t * p_hts, ble_evt_t * p_ble_evt)
{
ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
if (p_evt_write->handle == p_hts->meas_handles.cccd_handle)
{
on_cccd_write(p_hts, p_evt_write);
}
}
/**@brief Function for handling the HVC event.
*
* @details Handles HVC events from the BLE stack.
*
* @param[in] p_hts Health Thermometer Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_hvc(ble_hts_t * p_hts, ble_evt_t * p_ble_evt)
{
ble_gatts_evt_hvc_t * p_hvc = &p_ble_evt->evt.gatts_evt.params.hvc;
if (p_hvc->handle == p_hts->meas_handles.value_handle)
{
ble_hts_evt_t evt;
evt.evt_type = BLE_HTS_EVT_INDICATION_CONFIRMED;
p_hts->evt_handler(p_hts, &evt);
}
}
void ble_hts_on_ble_evt(ble_hts_t * p_hts, ble_evt_t * p_ble_evt)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_hts, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_hts, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_hts, p_ble_evt);
break;
case BLE_GATTS_EVT_HVC:
on_hvc(p_hts, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
/**@brief Function for encoding a Health Thermometer Measurement.
*
* @param[in] p_hts Health Thermometer Service structure.
* @param[in] p_hts_meas Measurement to be encoded.
* @param[out] p_encoded_buffer Buffer where the encoded data will be written.
*
* @return Size of encoded data.
*/
static uint8_t hts_measurement_encode(ble_hts_t * p_hts,
ble_hts_meas_t * p_hts_meas,
uint8_t * p_encoded_buffer)
{
uint8_t flags = 0;
uint8_t len = 1;
uint32_t encoded_temp;
// Flags field
if (p_hts_meas->temp_in_fahr_units)
{
flags |= HTS_MEAS_FLAG_TEMP_UNITS_BIT;
}
if (p_hts_meas->time_stamp_present)
{
flags |= HTS_MEAS_FLAG_TIME_STAMP_BIT;
}
// Temperature Measurement Value field
if (p_hts_meas->temp_in_fahr_units)
{
flags |= HTS_MEAS_FLAG_TEMP_UNITS_BIT;
encoded_temp = ((p_hts_meas->temp_in_fahr.exponent << 24) & 0xFF000000) |
((p_hts_meas->temp_in_fahr.mantissa << 0) & 0x00FFFFFF);
}
else
{
encoded_temp = ((p_hts_meas->temp_in_celcius.exponent << 24) & 0xFF000000) |
((p_hts_meas->temp_in_celcius.mantissa << 0) & 0x00FFFFFF);
}
len += uint32_encode(encoded_temp, &p_encoded_buffer[len]);
// Time Stamp field
if (p_hts_meas->time_stamp_present)
{
flags |= HTS_MEAS_FLAG_TIME_STAMP_BIT;
len += ble_date_time_encode(&p_hts_meas->time_stamp, &p_encoded_buffer[len]);
}
// Temperature Type field
if (p_hts_meas->temp_type_present)
{
flags |= HTS_MEAS_FLAG_TEMP_TYPE_BIT;
p_encoded_buffer[len++] = p_hts_meas->temp_type;
}
// Flags field
p_encoded_buffer[0] = flags;
return len;
}
/**@brief Function for adding Health Thermometer Measurement characteristics.
*
* @param[in] p_hts Health Thermometer Service structure.
* @param[in] p_hts_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t hts_measurement_char_add(ble_hts_t * p_hts, const ble_hts_init_t * p_hts_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_md_t cccd_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
ble_hts_meas_t initial_htm;
uint8_t encoded_htm[MAX_HTM_LEN];
memset(&cccd_md, 0, sizeof(cccd_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
cccd_md.write_perm = p_hts_init->hts_meas_attr_md.cccd_write_perm;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.indicate = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = &cccd_md;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_TEMPERATURE_MEASUREMENT_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.read_perm = p_hts_init->hts_meas_attr_md.read_perm;
attr_md.write_perm = p_hts_init->hts_meas_attr_md.write_perm;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
memset(&initial_htm, 0, sizeof(initial_htm));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = hts_measurement_encode(p_hts, &initial_htm, encoded_htm);
attr_char_value.init_offs = 0;
attr_char_value.max_len = MAX_HTM_LEN;
attr_char_value.p_value = encoded_htm;
return sd_ble_gatts_characteristic_add(p_hts->service_handle,
&char_md,
&attr_char_value,
&p_hts->meas_handles);
}
/**@brief Function for adding Temperature Type characteristics.
*
* @param[in] p_hts Health Thermometer Service structure.
* @param[in] p_hts_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t hts_temp_type_char_add(ble_hts_t * p_hts, const ble_hts_init_t * p_hts_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
uint8_t init_value_temp_type;
uint8_t init_value_encoded[1];
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_TEMPERATURE_TYPE_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.read_perm = p_hts_init->hts_temp_type_attr_md.read_perm;
attr_md.write_perm = p_hts_init->hts_temp_type_attr_md.write_perm;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 0;
memset(&attr_char_value, 0, sizeof(attr_char_value));
init_value_temp_type = p_hts_init->temp_type;
init_value_encoded[0] = init_value_temp_type;
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof (uint8_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = sizeof (uint8_t);
attr_char_value.p_value = init_value_encoded;
return sd_ble_gatts_characteristic_add(p_hts->service_handle,
&char_md,
&attr_char_value,
&p_hts->temp_type_handles);
}
uint32_t ble_hts_init(ble_hts_t * p_hts, const ble_hts_init_t * p_hts_init)
{
uint32_t err_code;
ble_uuid_t ble_uuid;
// Initialize service structure
p_hts->evt_handler = p_hts_init->evt_handler;
p_hts->conn_handle = BLE_CONN_HANDLE_INVALID;
p_hts->temp_type = p_hts_init->temp_type;
// Add service
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_HEALTH_THERMOMETER_SERVICE);
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_hts->service_handle);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add measurement characteristic
err_code = hts_measurement_char_add(p_hts, p_hts_init);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add temperature type characteristic
if (p_hts_init->temp_type_as_characteristic)
{
err_code = hts_temp_type_char_add(p_hts, p_hts_init);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
return NRF_SUCCESS;
}
uint32_t ble_hts_measurement_send(ble_hts_t * p_hts, ble_hts_meas_t * p_hts_meas)
{
uint32_t err_code;
// Send value if connected
if (p_hts->conn_handle != BLE_CONN_HANDLE_INVALID)
{
uint8_t encoded_hts_meas[MAX_HTM_LEN];
uint16_t len;
uint16_t hvx_len;
ble_gatts_hvx_params_t hvx_params;
len = hts_measurement_encode(p_hts, p_hts_meas, encoded_hts_meas);
hvx_len = len;
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_hts->meas_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_INDICATION;
hvx_params.offset = 0;
hvx_params.p_len = &hvx_len;
hvx_params.p_data = encoded_hts_meas;
err_code = sd_ble_gatts_hvx(p_hts->conn_handle, &hvx_params);
if ((err_code == NRF_SUCCESS) && (hvx_len != len))
{
err_code = NRF_ERROR_DATA_SIZE;
}
}
else
{
err_code = NRF_ERROR_INVALID_STATE;
}
return err_code;
}
uint32_t ble_hts_is_indication_enabled(ble_hts_t * p_hts, bool * p_indication_enabled)
{
uint32_t err_code;
uint8_t cccd_value_buf[BLE_CCCD_VALUE_LEN];
ble_gatts_value_t gatts_value;
// Initialize value struct.
memset(&gatts_value, 0, sizeof(gatts_value));
gatts_value.len = BLE_CCCD_VALUE_LEN;
gatts_value.offset = 0;
gatts_value.p_value = cccd_value_buf;
err_code = sd_ble_gatts_value_get(p_hts->conn_handle,
p_hts->meas_handles.cccd_handle,
&gatts_value);
if (err_code == NRF_SUCCESS)
{
*p_indication_enabled = ble_srv_is_indication_enabled(cccd_value_buf);
}
return err_code;
}

View File

@ -1,160 +0,0 @@
/* 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.
*/
/** @file
*
* @defgroup ble_sdk_srv_hts Health Thermometer Service
* @{
* @ingroup ble_sdk_srv
* @brief Health Thermometer Service module.
*
* @details This module implements the Health Thermometer Service.
*
* If an event handler is supplied by the application, the Health Thermometer
* Service will generate Health Thermometer Service events to the application.
*
* @note The application must propagate BLE stack events to the Health Thermometer Service
* module by calling ble_hts_on_ble_evt() from the @ref softdevice_handler function.
*
* @note Attention!
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_HTS_H__
#define BLE_HTS_H__
#include <stdint.h>
#include <stdbool.h>
#include "ble.h"
#include "ble_srv_common.h"
#include "ble_date_time.h"
// Temperature Type measurement locations
#define BLE_HTS_TEMP_TYPE_ARMPIT 1
#define BLE_HTS_TEMP_TYPE_BODY 2
#define BLE_HTS_TEMP_TYPE_EAR 3
#define BLE_HTS_TEMP_TYPE_FINGER 4
#define BLE_HTS_TEMP_TYPE_GI_TRACT 5
#define BLE_HTS_TEMP_TYPE_MOUTH 6
#define BLE_HTS_TEMP_TYPE_RECTUM 7
#define BLE_HTS_TEMP_TYPE_TOE 8
#define BLE_HTS_TEMP_TYPE_EAR_DRUM 9
/**@brief Health Thermometer Service event type. */
typedef enum
{
BLE_HTS_EVT_INDICATION_ENABLED, /**< Health Thermometer value indication enabled event. */
BLE_HTS_EVT_INDICATION_DISABLED, /**< Health Thermometer value indication disabled event. */
BLE_HTS_EVT_INDICATION_CONFIRMED /**< Confirmation of a temperature measurement indication has been received. */
} ble_hts_evt_type_t;
/**@brief Health Thermometer Service event. */
typedef struct
{
ble_hts_evt_type_t evt_type; /**< Type of event. */
} ble_hts_evt_t;
// Forward declaration of the ble_hts_t type.
typedef struct ble_hts_s ble_hts_t;
/**@brief Health Thermometer Service event handler type. */
typedef void (*ble_hts_evt_handler_t) (ble_hts_t * p_hts, ble_hts_evt_t * p_evt);
/**@brief FLOAT format (IEEE-11073 32-bit FLOAT, defined as a 32-bit value with a 24-bit mantissa
* and an 8-bit exponent. */
typedef struct
{
int8_t exponent; /**< Base 10 exponent */
int32_t mantissa; /**< Mantissa, should be using only 24 bits */
} ieee_float32_t;
/**@brief Health Thermometer Service init structure. This contains all options and data
* needed for initialization of the service. */
typedef struct
{
ble_hts_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Health Thermometer Service. */
ble_srv_cccd_security_mode_t hts_meas_attr_md; /**< Initial security level for health thermometer measurement attribute */
ble_srv_security_mode_t hts_temp_type_attr_md; /**< Initial security level for health thermometer tempearture type attribute */
uint8_t temp_type_as_characteristic; /**< Set non-zero if temp type given as characteristic */
uint8_t temp_type; /**< Temperature type if temperature characteristic is used */
} ble_hts_init_t;
/**@brief Health Thermometer Service structure. This contains various status information for
* the service. */
struct ble_hts_s
{
ble_hts_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Health Thermometer Service. */
uint16_t service_handle; /**< Handle of Health Thermometer Service (as provided by the BLE stack). */
ble_gatts_char_handles_t meas_handles; /**< Handles related to the Health Thermometer Measurement characteristic. */
ble_gatts_char_handles_t temp_type_handles; /**< Handles related to the Health Thermometer Temperature Type characteristic. */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
uint8_t temp_type; /**< Temperature type indicates where the measurement was taken. */
};
/**@brief Health Thermometer Service measurement structure. This contains a Health Thermometer
* measurement. */
typedef struct ble_hts_meas_s
{
bool temp_in_fahr_units; /**< True if Temperature is in Fahrenheit units, Celcius otherwise. */
bool time_stamp_present; /**< True if Time Stamp is present. */
bool temp_type_present; /**< True if Temperature Type is present. */
ieee_float32_t temp_in_celcius; /**< Temperature Measurement Value (Celcius). */
ieee_float32_t temp_in_fahr; /**< Temperature Measurement Value (Fahrenheit). */
ble_date_time_t time_stamp; /**< Time Stamp. */
uint8_t temp_type; /**< Temperature Type. */
} ble_hts_meas_t;
/**@brief Function for initializing the Health Thermometer Service.
*
* @param[out] p_hts Health Thermometer Service structure. This structure will have to
* be supplied by the application. It will be initialized by this function,
* and will later be used to identify this particular service instance.
* @param[in] p_hts_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
*/
uint32_t ble_hts_init(ble_hts_t * p_hts, const ble_hts_init_t * p_hts_init);
/**@brief Function for handling the Application's BLE Stack events.
*
* @details Handles all events from the BLE stack of interest to the Health Thermometer Service.
*
* @param[in] p_hts Health Thermometer Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_hts_on_ble_evt(ble_hts_t * p_hts, ble_evt_t * p_ble_evt);
/**@brief Function for sending health thermometer measurement if indication has been enabled.
*
* @details The application calls this function after having performed a Health Thermometer
* measurement. If indication has been enabled, the measurement data is encoded and
* sent to the client.
*
* @param[in] p_hts Health Thermometer Service structure.
* @param[in] p_hts_meas Pointer to new health thermometer measurement.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
uint32_t ble_hts_measurement_send(ble_hts_t * p_hts, ble_hts_meas_t * p_hts_meas);
/**@brief Function for checking if indication of Temperature Measurement is currently enabled.
*
* @param[in] p_hts Health Thermometer Service structure.
* @param[out] p_indication_enabled TRUE if indication is enabled, FALSE otherwise.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
uint32_t ble_hts_is_indication_enabled(ble_hts_t * p_hts, bool * p_indication_enabled);
#endif // BLE_HTS_H__
/** @} */

View File

@ -1,173 +0,0 @@
/* 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.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#include "ble_ias.h"
#include <string.h>
#include "ble_srv_common.h"
#define INITIAL_ALERT_LEVEL BLE_CHAR_ALERT_LEVEL_NO_ALERT
/**@brief Function for handling the Connect event.
*
* @param[in] p_ias Immediate Alert Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_connect(ble_ias_t * p_ias, ble_evt_t * p_ble_evt)
{
p_ias->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}
/**@brief Function for handling the Write event.
*
* @param[in] p_ias Immediate Alert Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_write(ble_ias_t * p_ias, ble_evt_t * p_ble_evt)
{
ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
if ((p_evt_write->handle == p_ias->alert_level_handles.value_handle) && (p_evt_write->len == 1))
{
// Alert level written, call application event handler
ble_ias_evt_t evt;
evt.evt_type = BLE_IAS_EVT_ALERT_LEVEL_UPDATED;
evt.params.alert_level = p_evt_write->data[0];
p_ias->evt_handler(p_ias, &evt);
}
}
void ble_ias_on_ble_evt(ble_ias_t * p_ias, ble_evt_t * p_ble_evt)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_ias, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_ias, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
/**@brief Function for adding Alert Level characteristics.
*
* @param[in] p_ias Immediate Alert Service structure.
* @param[in] p_ias_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t alert_level_char_add(ble_ias_t * p_ias)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
uint8_t initial_alert_level;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.write_wo_resp = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_ALERT_LEVEL_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 0;
memset(&attr_char_value, 0, sizeof(attr_char_value));
initial_alert_level = INITIAL_ALERT_LEVEL;
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof (uint8_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = sizeof (uint8_t);
attr_char_value.p_value = &initial_alert_level;
return sd_ble_gatts_characteristic_add(p_ias->service_handle,
&char_md,
&attr_char_value,
&p_ias->alert_level_handles);
}
uint32_t ble_ias_init(ble_ias_t * p_ias, const ble_ias_init_t * p_ias_init)
{
uint32_t err_code;
ble_uuid_t ble_uuid;
// Initialize service structure
if (p_ias_init->evt_handler == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
p_ias->evt_handler = p_ias_init->evt_handler;
// Add service
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_IMMEDIATE_ALERT_SERVICE);
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
&ble_uuid,
&p_ias->service_handle);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add alert level characteristic
return alert_level_char_add(p_ias);
}
uint32_t ble_ias_alert_level_get(ble_ias_t * p_ias, uint8_t * p_alert_level)
{
ble_gatts_value_t gatts_value;
// Initialize value struct.
memset(&gatts_value, 0, sizeof(gatts_value));
gatts_value.len = sizeof(uint8_t);
gatts_value.offset = 0;
gatts_value.p_value = p_alert_level;
return sd_ble_gatts_value_get(p_ias->conn_handle,
p_ias->alert_level_handles.value_handle,
&gatts_value);
}

View File

@ -1,113 +0,0 @@
/* 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_ias Immediate Alert Service
* @{
* @ingroup ble_sdk_srv
* @brief Immediate Alert Service module.
*
* @details This module implements the Immediate Alert Service with the Alert Level characteristic.
* During initialization it adds the Immediate Alert Service and Alert Level characteristic
* to the BLE stack database.
*
* The application must supply an event handler for receiving Immediate Alert Service
* events. Using this handler, the service will notify the application when the
* Alert Level characteristic value changes.
*
* The service also provides a function for letting the application poll the current
* value of the Alert Level characteristic.
*
* @note The application must propagate BLE stack events to the Immediate Alert Service
* module by calling ble_ias_on_ble_evt() from the @ref softdevice_handler callback.
*
* @note Attention!
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_IAS_H__
#define BLE_IAS_H__
#include <stdint.h>
#include "ble.h"
/**@brief Immediate Alert Service event type. */
typedef enum
{
BLE_IAS_EVT_ALERT_LEVEL_UPDATED /**< Alert Level Updated event. */
} ble_ias_evt_type_t;
/**@brief Immediate Alert Service event. */
typedef struct
{
ble_ias_evt_type_t evt_type; /**< Type of event. */
union
{
uint8_t alert_level; /**< New Alert Level value. */
} params;
} ble_ias_evt_t;
// Forward declaration of the ble_ias_t type.
typedef struct ble_ias_s ble_ias_t;
/**@brief Immediate Alert Service event handler type. */
typedef void (*ble_ias_evt_handler_t) (ble_ias_t * p_ias, ble_ias_evt_t * p_evt);
/**@brief Immediate Alert Service init structure. This contains all options and data needed for
* initialization of the service. */
typedef struct
{
ble_ias_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Immediate Alert Service. */
} ble_ias_init_t;
/**@brief Immediate Alert Service structure. This contains various status information for the
* service. */
struct ble_ias_s
{
ble_ias_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Immediate Alert Service. */
uint16_t service_handle; /**< Handle of Immediate Alert Service (as provided by the BLE stack). */
ble_gatts_char_handles_t alert_level_handles; /**< Handles related to the Alert Level characteristic. */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
};
/**@brief Function for initializing the Immediate Alert Service.
*
* @param[out] p_ias Immediate Alert Service structure. This structure will have to be
* supplied by the application. It will be initialized by this function,
* and will later be used to identify this particular service instance.
* @param[in] p_ias_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
*/
uint32_t ble_ias_init(ble_ias_t * p_ias, const ble_ias_init_t * p_ias_init);
/**@brief Function for handling the Application's BLE Stack events.
*
* @details Handles all events from the BLE stack of interest to the Immediate Alert Service.
*
* @param[in] p_ias Immediate Alert Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_ias_on_ble_evt(ble_ias_t * p_ias, ble_evt_t * p_ble_evt);
/**@brief Function for getting current value of the Alert Level characteristic.
*
* @param[in] p_ias Immediate Alert Service structure.
* @param[out] p_alert_level Current Alert Level value.
*/
uint32_t ble_ias_alert_level_get(ble_ias_t * p_ias, uint8_t * p_alert_level);
#endif // BLE_IAS_H__
/** @} */

View File

@ -1,189 +0,0 @@
/* 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 "ble_ias_c.h"
#include <string.h>
#include "sdk_common.h"
#include "ble.h"
#include "ble_srv_common.h"
#include "ble_gattc.h"
#include "ble_db_discovery.h"
void ble_ias_c_on_db_disc_evt(ble_ias_c_t * p_ias_c, const ble_db_discovery_evt_t * p_evt)
{
ble_ias_c_evt_t evt;
memset(&evt, 0, sizeof(ble_ias_c_evt_t));
evt.evt_type = BLE_IAS_C_EVT_DISCOVERY_FAILED;
evt.conn_handle = p_evt->conn_handle;
const ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;
// Check if the Immediate Alert Service was discovered.
if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE
&&
p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_IMMEDIATE_ALERT_SERVICE
&&
p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
{
uint32_t i;
for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
// The Alert Level characteristic in the Immediate Alert Service instance is found
// on peer. Check if it has the correct property 'Write without response'.
switch(p_chars[i].characteristic.uuid.uuid)
{
case BLE_UUID_ALERT_LEVEL_CHAR:
if(p_chars[i].characteristic.char_props.write_wo_resp)
{
// Found Alert Level characteristic inside the Immediate Alert Service.
memcpy(&evt.alert_level,
&p_chars[i].characteristic,
sizeof(ble_gattc_char_t));
}
break;
default:
break;
}
}
}
if (evt.alert_level.handle_value != BLE_GATT_HANDLE_INVALID)
{
evt.evt_type = BLE_IAS_C_EVT_DISCOVERY_COMPLETE;
}
p_ias_c->evt_handler(p_ias_c, &evt);
}
uint32_t ble_ias_c_init(ble_ias_c_t * p_ias_c, ble_ias_c_init_t const * p_ias_c_init)
{
VERIFY_PARAM_NOT_NULL(p_ias_c);
VERIFY_PARAM_NOT_NULL(p_ias_c_init->evt_handler);
VERIFY_PARAM_NOT_NULL(p_ias_c_init);
p_ias_c->evt_handler = p_ias_c_init->evt_handler;
p_ias_c->error_handler = p_ias_c_init->error_handler;
p_ias_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ias_c->alert_level_char.handle_value = BLE_GATT_HANDLE_INVALID;
BLE_UUID_BLE_ASSIGN(p_ias_c->alert_level_char.uuid, BLE_UUID_ALERT_LEVEL_CHAR);
BLE_UUID_BLE_ASSIGN(p_ias_c->service_uuid, BLE_UUID_IMMEDIATE_ALERT_SERVICE);
return ble_db_discovery_evt_register(&p_ias_c->service_uuid);
}
/**@brief Function for handling the Disconnect event.
*
* @param[in] p_ias_c Immediate Alert Service client structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_disconnect(ble_ias_c_t * p_ias_c, ble_evt_t const * p_ble_evt)
{
// The following values will be re-initialized when a new connection is made.
p_ias_c->conn_handle = BLE_CONN_HANDLE_INVALID;
if (ble_ias_c_is_discovered(p_ias_c))
{
// There was a valid instance of IAS on the peer. Send an event to the
// application, so that it can do any clean up related to this module.
ble_ias_c_evt_t evt;
evt.evt_type = BLE_IAS_C_EVT_DISCONN_COMPLETE;
p_ias_c->evt_handler(p_ias_c, &evt);
p_ias_c->alert_level_char.handle_value = BLE_GATT_HANDLE_INVALID;
}
}
void ble_ias_c_on_ble_evt(ble_ias_c_t * p_ias_c, ble_evt_t const * p_ble_evt)
{
uint32_t err_code = NRF_SUCCESS;
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_ias_c, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
if (err_code != NRF_SUCCESS && p_ias_c->error_handler != 0)
{
p_ias_c->error_handler(err_code);
}
}
/**@brief Function for performing a Write procedure.
*
* @param[in] conn_handle Handle of the connection on which to perform the write operation.
* @param[in] write_handle Handle of the attribute to be written.
* @param[in] length Length of data to be written.
* @param[in] p_value Data to be written.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t write_characteristic_value(uint16_t conn_handle,
uint16_t write_handle,
uint16_t length,
uint8_t * p_value)
{
ble_gattc_write_params_t write_params;
memset(&write_params, 0, sizeof(write_params));
write_params.handle = write_handle;
write_params.write_op = BLE_GATT_OP_WRITE_CMD;
write_params.offset = 0;
write_params.len = length;
write_params.p_value = p_value;
return sd_ble_gattc_write(conn_handle, &write_params);
}
uint32_t ble_ias_c_send_alert_level(ble_ias_c_t const * p_ias_c, uint8_t alert_level)
{
if (!ble_ias_c_is_discovered(p_ias_c))
{
return NRF_ERROR_NOT_FOUND;
}
return write_characteristic_value(p_ias_c->conn_handle,
p_ias_c->alert_level_char.handle_value,
sizeof(uint8_t),
&alert_level);
}
uint32_t ble_ias_c_handles_assign(ble_ias_c_t * p_ias_c,
const uint16_t conn_handle,
const uint16_t alert_level_handle)
{
VERIFY_PARAM_NOT_NULL(p_ias_c);
p_ias_c->conn_handle = conn_handle;
p_ias_c->alert_level_char.handle_value = alert_level_handle;
return NRF_SUCCESS;
}

View File

@ -1,168 +0,0 @@
/* 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_ias_c Immediate Alert Service Client
* @{
* @ingroup ble_sdk_srv
* @brief Immediate Alert Service Client module
*
* @details This module implements the Immediate Alert Service client - locator role of the Find Me
* profile. On @ref BLE_GAP_EVT_CONNECTED event, this module starts discovery of the
* Immediate Alert Service with Alert Level characteristic at the peer. This module will
* indicate the application about a successful service & characteristic discovery using
* @ref BLE_IAS_C_EVT_DISCOVERY_COMPLETE event. The application can use @ref
* ble_ias_c_send_alert_level function to signal alerts to the peer.
*
* @note The application must propagate BLE stack events to this module by calling
* ble_ias_c_on_ble_evt() from the @ref softdevice_handler callback function.
*/
#ifndef BLE_IAS_C_H__
#define BLE_IAS_C_H__
#include <stdint.h>
#include "ble_srv_common.h"
#include "ble_gattc.h"
#include "ble.h"
#include "ble_db_discovery.h"
// Forward declaration of the ble_ias_c_t type.
typedef struct ble_ias_c_s ble_ias_c_t;
/**@brief Immediate Alert Service client event type. */
typedef enum
{
BLE_IAS_C_EVT_DISCOVERY_COMPLETE, /**< Event indicating that the Immediate Alert Service is found at the peer. */
BLE_IAS_C_EVT_DISCOVERY_FAILED, /**< Event indicating that the Immediate Alert Service is not found at the peer. */
BLE_IAS_C_EVT_DISCONN_COMPLETE /**< Event indicating that the Immediate Alert Service client module has completed the processing of BLE_GAP_EVT_DISCONNECTED event. This event is raised only if a valid instance of IAS was found at the peer during the discovery phase. This event can be used the application to do clean up related to the IAS Client.*/
} ble_ias_c_evt_type_t;
/**@brief Immediate Alert Service client event. */
typedef struct
{
ble_ias_c_evt_type_t evt_type; /**< Type of event. */
uint16_t conn_handle; /**< Connection handle on which the IAS service was discovered on the peer device. This will be filled if the evt_type is @ref BLE_IAS_C_EVT_DISCOVERY_COMPLETE.*/
ble_gattc_char_t alert_level; /**< Info on the discovered Alert Level characteristic discovered. This will be filled if the evt_type is @ref BLE_IAS_C_EVT_DISCOVERY_COMPLETE.*/
} ble_ias_c_evt_t;
/**@brief Immediate Alert Service client event handler type. */
typedef void (*ble_ias_c_evt_handler_t) (ble_ias_c_t * p_ias_c, ble_ias_c_evt_t * p_evt);
/**@brief IAS Client structure. This contains various status information for the client. */
struct ble_ias_c_s
{
ble_ias_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Immediate Alert Service client. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
uint16_t conn_handle; /**< Handle of the current connection. Set with @ref ble_ias_c_handles_assign when connected. */
ble_uuid_t service_uuid; /**< The GATT Service holding the discovered Immediate Service. */
ble_gattc_char_t alert_level_char; /**< IAS Alert Level Characteristic. Stores data about the alert characteristic found on the peer. */
};
/**@brief IAS Client init structure. This contains all options and data needed for initialization of
* the client.*/
typedef struct
{
ble_ias_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events from the Immediate Alert Service client. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
} ble_ias_c_init_t;
/**@brief Function for initializing the Immediate Alert Service client.
*
* @details This call allows the application to initialize the Immediate Alert Service client.
*
* @param[out] p_ias_c Immediate Alert Service client structure. This structure will have to
* be supplied by the application. It will be initialized by this
* function, and will later be used to identify this particular client
* instance.
* @param[in] p_ias_c_init Information needed to initialize the Immediate Alert Service client.
*
* @return NRF_SUCCESS on successful initialization of service.
*/
uint32_t ble_ias_c_init(ble_ias_c_t * p_ias_c, const ble_ias_c_init_t * p_ias_c_init);
/**@brief Function for sending alert level to the peer.
*
* @details This function allows the application to send an alert to the peer.
*
* @param[in] p_ias_c Immediate Alert Service client structure.
* @param[in] alert_level Required alert level to be sent to the peer.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
uint32_t ble_ias_c_send_alert_level(const ble_ias_c_t * p_ias_c, uint8_t alert_level);
/**@brief Function for handling the Application's BLE Stack events for Immediate Alert Service client.
*
* @details Handles all events from the BLE stack of interest to the Immediate Alert Service client.
*
* @param[in] p_ias_c Immediate Alert Service client structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_ias_c_on_ble_evt(ble_ias_c_t * p_ias_c, const ble_evt_t * p_ble_evt);
/**@brief Function for checking whether the peer's Immediate Alert Service instance and the alert level
* characteristic have been discovered.
*
* @param[in] p_ias_c Immediate Alert Service client structure.
*
* @return TRUE if a handle has been assigned to alert_level_handle, meaning it must have been
* discovered. FALSE if the handle is invalid.
*/
static __INLINE bool ble_ias_c_is_discovered(const ble_ias_c_t * p_ias_c)
{
return (p_ias_c->alert_level_char.handle_value != BLE_GATT_HANDLE_INVALID);
}
/**@brief Function for handling events from the database discovery module.
*
* @details Call this function when getting a callback event from the DB discovery modue.
* This function will handle an event from the database discovery module, and determine
* if it relates to the discovery of heart rate service at the peer. If so, it will
* call the application's event handler indicating that the heart rate 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_ias_c Pointer to the immediate alert client structure instance that will handle
* the discovery.
* @param[in] p_evt Pointer to the event received from the database discovery module.
*
*/
void ble_ias_c_on_db_disc_evt(ble_ias_c_t * p_ias_c, const ble_db_discovery_evt_t * p_evt);
/**@brief Function for assigning handles to an instance of ias_c.
*
* @details Call this function when a link has been established with a peer to
* associate this link to this instance of the module. This makes it
* possible to handle several links and associate each link to a particular
* instance of this module. The connection handle and attribute handles will be
* provided from the discovery event @ref BLE_IAS_C_EVT_DISCOVERY_COMPLETE.
*
* @param[in] p_ias_c Pointer to the IAS client structure instance to associate.
* @param[in] conn_handle Connection handle to associated with the given IAS Instance.
* @param[in] alert_level_handle Attribute handle on the IAS server that you want this IAS_C client to
* interact with.
*
* @retval NRF_SUCCESS If the operation was successful.
* @retval NRF_ERROR_NULL If a p_ias_c was a NULL pointer.
*/
uint32_t ble_ias_c_handles_assign(ble_ias_c_t * p_ias_c,
uint16_t conn_handle,
uint16_t alert_level_handle);
#endif // BLE_IAS_C_H__
/** @} */

View File

@ -1,228 +0,0 @@
/* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the license.txt file.
*/
#include "ble_lbs.h"
#include "ble_srv_common.h"
#include "sdk_common.h"
/**@brief Function for handling the Connect event.
*
* @param[in] p_lbs LED Button Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_connect(ble_lbs_t * p_lbs, ble_evt_t * p_ble_evt)
{
p_lbs->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}
/**@brief Function for handling the Disconnect event.
*
* @param[in] p_lbs LED Button Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_disconnect(ble_lbs_t * p_lbs, ble_evt_t * p_ble_evt)
{
UNUSED_PARAMETER(p_ble_evt);
p_lbs->conn_handle = BLE_CONN_HANDLE_INVALID;
}
/**@brief Function for handling the Write event.
*
* @param[in] p_lbs LED Button Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_write(ble_lbs_t * p_lbs, ble_evt_t * p_ble_evt)
{
ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
if ((p_evt_write->handle == p_lbs->led_char_handles.value_handle) &&
(p_evt_write->len == 1) &&
(p_lbs->led_write_handler != NULL))
{
p_lbs->led_write_handler(p_lbs, p_evt_write->data[0]);
}
}
void ble_lbs_on_ble_evt(ble_lbs_t * p_lbs, ble_evt_t * p_ble_evt)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_lbs, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_lbs, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_lbs, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
/**@brief Function for adding the LED Characteristic.
*
* @param[in] p_lbs LED Button Service structure.
* @param[in] p_lbs_init LED Button Service initialization structure.
*
* @retval NRF_SUCCESS on success, else an error value from the SoftDevice
*/
static uint32_t led_char_add(ble_lbs_t * p_lbs, const ble_lbs_init_t * p_lbs_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.char_props.write = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
ble_uuid.type = p_lbs->uuid_type;
ble_uuid.uuid = LBS_UUID_LED_CHAR;
memset(&attr_md, 0, sizeof(attr_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 0;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof(uint8_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = sizeof(uint8_t);
attr_char_value.p_value = NULL;
return sd_ble_gatts_characteristic_add(p_lbs->service_handle,
&char_md,
&attr_char_value,
&p_lbs->led_char_handles);
}
/**@brief Function for adding the Button Characteristic.
*
* @param[in] p_lbs LED Button Service structure.
* @param[in] p_lbs_init LED Button Service initialization structure.
*
* @retval NRF_SUCCESS on success, else an error value from the SoftDevice
*/
static uint32_t button_char_add(ble_lbs_t * p_lbs, const ble_lbs_init_t * p_lbs_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_md_t cccd_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
memset(&cccd_md, 0, sizeof(cccd_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.char_props.notify = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = &cccd_md;
char_md.p_sccd_md = NULL;
ble_uuid.type = p_lbs->uuid_type;
ble_uuid.uuid = LBS_UUID_BUTTON_CHAR;
memset(&attr_md, 0, sizeof(attr_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 0;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof(uint8_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = sizeof(uint8_t);
attr_char_value.p_value = NULL;
return sd_ble_gatts_characteristic_add(p_lbs->service_handle,
&char_md,
&attr_char_value,
&p_lbs->button_char_handles);
}
uint32_t ble_lbs_init(ble_lbs_t * p_lbs, const ble_lbs_init_t * p_lbs_init)
{
uint32_t err_code;
ble_uuid_t ble_uuid;
// Initialize service structure.
p_lbs->conn_handle = BLE_CONN_HANDLE_INVALID;
p_lbs->led_write_handler = p_lbs_init->led_write_handler;
// Add service.
ble_uuid128_t base_uuid = {LBS_UUID_BASE};
err_code = sd_ble_uuid_vs_add(&base_uuid, &p_lbs->uuid_type);
VERIFY_SUCCESS(err_code);
ble_uuid.type = p_lbs->uuid_type;
ble_uuid.uuid = LBS_UUID_SERVICE;
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_lbs->service_handle);
VERIFY_SUCCESS(err_code);
// Add characteristics.
err_code = button_char_add(p_lbs, p_lbs_init);
VERIFY_SUCCESS(err_code);
err_code = led_char_add(p_lbs, p_lbs_init);
VERIFY_SUCCESS(err_code);
return NRF_SUCCESS;
}
uint32_t ble_lbs_on_button_change(ble_lbs_t * p_lbs, uint8_t button_state)
{
ble_gatts_hvx_params_t params;
uint16_t len = sizeof(button_state);
memset(&params, 0, sizeof(params));
params.type = BLE_GATT_HVX_NOTIFICATION;
params.handle = p_lbs->button_char_handles.value_handle;
params.p_data = &button_state;
params.p_len = &len;
return sd_ble_gatts_hvx(p_lbs->conn_handle, &params);
}

View File

@ -1,104 +0,0 @@
/* Copyright (c) 2015 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_lbs LED Button Service Server
* @{
* @ingroup ble_sdk_srv
*
* @brief LED Button Service Server module.
*
* @details This module implements a custom LED Button Service with an LED and Button Characteristics.
* During initialization, the module adds the LED Button Service and Characteristics
* to the BLE stack database.
*
* The application must supply an event handler for receiving LED Button Service
* events. Using this handler, the service notifies the application when the
* LED value changes.
*
* The service also provides a function for letting the application notify
* the state of the Button Characteristic to connected peers.
*
* @note The application must propagate BLE stack events to the LED Button Service
* module by calling ble_lbs_on_ble_evt() from the @ref softdevice_handler callback.
*/
#ifndef BLE_LBS_H__
#define BLE_LBS_H__
#include <stdint.h>
#include <stdbool.h>
#include "ble.h"
#include "ble_srv_common.h"
#define LBS_UUID_BASE {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, \
0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00}
#define LBS_UUID_SERVICE 0x1523
#define LBS_UUID_BUTTON_CHAR 0x1524
#define LBS_UUID_LED_CHAR 0x1525
// Forward declaration of the ble_lbs_t type.
typedef struct ble_lbs_s ble_lbs_t;
typedef void (*ble_lbs_led_write_handler_t) (ble_lbs_t * p_lbs, uint8_t new_state);
/** @brief LED Button Service init structure. This structure contains all options and data needed for
* initialization of the service.*/
typedef struct
{
ble_lbs_led_write_handler_t led_write_handler; /**< Event handler to be called when the LED Characteristic is written. */
} ble_lbs_init_t;
/**@brief LED Button Service structure. This structure contains various status information for the service. */
struct ble_lbs_s
{
uint16_t service_handle; /**< Handle of LED Button Service (as provided by the BLE stack). */
ble_gatts_char_handles_t led_char_handles; /**< Handles related to the LED Characteristic. */
ble_gatts_char_handles_t button_char_handles; /**< Handles related to the Button Characteristic. */
uint8_t uuid_type; /**< UUID type for the LED Button Service. */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack). BLE_CONN_HANDLE_INVALID if not in a connection. */
ble_lbs_led_write_handler_t led_write_handler; /**< Event handler to be called when the LED Characteristic is written. */
};
/**@brief Function for initializing the LED Button Service.
*
* @param[out] p_lbs LED Button Service structure. This structure must be supplied by
* the application. It is initialized by this function and will later
* be used to identify this particular service instance.
* @param[in] p_lbs_init Information needed to initialize the service.
*
* @retval NRF_SUCCESS If the service was initialized successfully. Otherwise, an error code is returned.
*/
uint32_t ble_lbs_init(ble_lbs_t * p_lbs, const ble_lbs_init_t * p_lbs_init);
/**@brief Function for handling the application's BLE stack events.
*
* @details This function handles all events from the BLE stack that are of interest to the LED Button Service.
*
* @param[in] p_lbs LED Button Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_lbs_on_ble_evt(ble_lbs_t * p_lbs, ble_evt_t * p_ble_evt);
/**@brief Function for sending a button state notification.
*
* @param[in] p_lbs LED Button Service structure.
* @param[in] button_state New button state.
*
* @retval NRF_SUCCESS If the notification was sent successfully. Otherwise, an error code is returned.
*/
uint32_t ble_lbs_on_button_change(ble_lbs_t * p_lbs, uint8_t button_state);
#endif // BLE_LBS_H__
/** @} */

View File

@ -1,362 +0,0 @@
/*
* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is confidential property of Nordic Semiconductor. The use,
* copying, transfer or disclosure of such information is prohibited except by express written
* agreement with Nordic Semiconductor.
*
*/
#include "ble_lbs_c.h"
#include "ble_db_discovery.h"
#include "ble_types.h"
#include "ble_srv_common.h"
#include "ble_gattc.h"
#include "app_trace.h"
#include "sdk_common.h"
#include "nrf_log.h"
#define LOG NRF_LOG_PRINTF_DEBUG /**< Debug logger macro that will be used in this file to do logging of important information over UART. */
#define TX_BUFFER_MASK 0x07 /**< TX Buffer mask, must be a mask of continuous zeroes, followed by continuous 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 BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
#define WRITE_MESSAGE_LENGTH BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
typedef enum
{
READ_REQ, /**< Type identifying that this tx_message is a read request. */
WRITE_REQ /**< Type identifying that this tx_message is a write request. */
} tx_request_t;
/**@brief Structure for writing a message to the peer, i.e. 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 central.
*/
typedef struct
{
uint16_t conn_handle; /**< Connection handle to be used when transmitting this message. */
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 central. */
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. */
/**@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)
{
LOG("[LBS_C]: SD Read/Write API returns Success..\r\n");
m_tx_index++;
m_tx_index &= TX_BUFFER_MASK;
}
else
{
LOG("[LBS_C]: SD Read/Write API returns error. This message sending will be "
"attempted again..\r\n");
}
}
}
/**@brief Function for handling write response events.
*
* @param[in] p_ble_lbs_c Pointer to the Led Button Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_write_rsp(ble_lbs_c_t * p_ble_lbs_c, const ble_evt_t * p_ble_evt)
{
// Check if the event if on the link for this instance
if (p_ble_lbs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
{
return;
}
// Check if there is any message to be sent across to the peer and send it.
tx_buffer_process();
}
/**@brief Function for handling Handle Value Notification received from the SoftDevice.
*
* @details This function will uses the Handle Value Notification received from the SoftDevice
* and checks if it is a notification of Button state from the peer. If
* it is, this function will decode the state of the button and send it to the
* application.
*
* @param[in] p_ble_lbs_c Pointer to the Led Button Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_hvx(ble_lbs_c_t * p_ble_lbs_c, const ble_evt_t * p_ble_evt)
{
// Check if the event is on the link for this instance
if (p_ble_lbs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
{
return;
}
// Check if this is a Button notification.
if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_lbs_c->peer_lbs_db.button_handle)
{
if (p_ble_evt->evt.gattc_evt.params.hvx.len == 1)
{
ble_lbs_c_evt_t ble_lbs_c_evt;
ble_lbs_c_evt.evt_type = BLE_LBS_C_EVT_BUTTON_NOTIFICATION;
ble_lbs_c_evt.conn_handle = p_ble_lbs_c->conn_handle;
ble_lbs_c_evt.params.button.button_state = p_ble_evt->evt.gattc_evt.params.hvx.data[0];
p_ble_lbs_c->evt_handler(p_ble_lbs_c, &ble_lbs_c_evt);
}
}
}
/**@brief Function for handling Disconnected event received from the SoftDevice.
*
* @details This function check if the disconnect event is happening on the link
* associated with the current instance of the module, if so it will set its
* conn_handle to invalid.
*
* @param[in] p_ble_lbs_c Pointer to the Led Button Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_disconnected(ble_lbs_c_t * p_ble_lbs_c, const ble_evt_t * p_ble_evt)
{
if (p_ble_lbs_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
{
p_ble_lbs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ble_lbs_c->peer_lbs_db.button_cccd_handle = BLE_GATT_HANDLE_INVALID;
p_ble_lbs_c->peer_lbs_db.button_handle = BLE_GATT_HANDLE_INVALID;
p_ble_lbs_c->peer_lbs_db.led_handle = BLE_GATT_HANDLE_INVALID;
}
}
void ble_lbs_on_db_disc_evt(ble_lbs_c_t * p_ble_lbs_c, const ble_db_discovery_evt_t * p_evt)
{
// Check if the Led Button Service was discovered.
if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
p_evt->params.discovered_db.srv_uuid.uuid == LBS_UUID_SERVICE &&
p_evt->params.discovered_db.srv_uuid.type == p_ble_lbs_c->uuid_type)
{
ble_lbs_c_evt_t evt;
evt.evt_type = BLE_LBS_C_EVT_DISCOVERY_COMPLETE;
evt.conn_handle = p_evt->conn_handle;
uint32_t i;
for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
const ble_gatt_db_char_t * p_char = &(p_evt->params.discovered_db.charateristics[i]);
switch(p_char->characteristic.uuid.uuid)
{
case LBS_UUID_LED_CHAR:
evt.params.peer_db.led_handle = p_char->characteristic.handle_value;
break;
case LBS_UUID_BUTTON_CHAR:
evt.params.peer_db.button_handle = p_char->characteristic.handle_value;
evt.params.peer_db.button_cccd_handle = p_char->cccd_handle;
break;
default:
break;
}
}
LOG("[LBS_C]: Led Button Service discovered at peer.\r\n");
//If the instance has been assigned prior to db_discovery, assign the db_handles
if(p_ble_lbs_c->conn_handle != BLE_CONN_HANDLE_INVALID)
{
if ((p_ble_lbs_c->peer_lbs_db.led_handle == BLE_GATT_HANDLE_INVALID)&&
(p_ble_lbs_c->peer_lbs_db.button_handle == BLE_GATT_HANDLE_INVALID)&&
(p_ble_lbs_c->peer_lbs_db.button_cccd_handle == BLE_GATT_HANDLE_INVALID))
{
p_ble_lbs_c->peer_lbs_db = evt.params.peer_db;
}
}
p_ble_lbs_c->evt_handler(p_ble_lbs_c, &evt);
}
}
uint32_t ble_lbs_c_init(ble_lbs_c_t * p_ble_lbs_c, ble_lbs_c_init_t * p_ble_lbs_c_init)
{
uint32_t err_code;
ble_uuid_t lbs_uuid;
ble_uuid128_t lbs_base_uuid = {LBS_UUID_BASE};
VERIFY_PARAM_NOT_NULL(p_ble_lbs_c);
VERIFY_PARAM_NOT_NULL(p_ble_lbs_c_init);
VERIFY_PARAM_NOT_NULL(p_ble_lbs_c_init->evt_handler);
p_ble_lbs_c->peer_lbs_db.button_cccd_handle = BLE_GATT_HANDLE_INVALID;
p_ble_lbs_c->peer_lbs_db.button_handle = BLE_GATT_HANDLE_INVALID;
p_ble_lbs_c->peer_lbs_db.led_handle = BLE_GATT_HANDLE_INVALID;
p_ble_lbs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ble_lbs_c->evt_handler = p_ble_lbs_c_init->evt_handler;
err_code = sd_ble_uuid_vs_add(&lbs_base_uuid, &p_ble_lbs_c->uuid_type);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
VERIFY_SUCCESS(err_code);
lbs_uuid.type = p_ble_lbs_c->uuid_type;
lbs_uuid.uuid = LBS_UUID_SERVICE;
return ble_db_discovery_evt_register(&lbs_uuid);
}
void ble_lbs_c_on_ble_evt(ble_lbs_c_t * p_ble_lbs_c, const ble_evt_t * p_ble_evt)
{
if ((p_ble_lbs_c == NULL) || (p_ble_evt == NULL))
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_GATTC_EVT_HVX:
on_hvx(p_ble_lbs_c, p_ble_evt);
break;
case BLE_GATTC_EVT_WRITE_RSP:
on_write_rsp(p_ble_lbs_c, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnected(p_ble_lbs_c, p_ble_evt);
break;
default:
break;
}
}
/**@brief Function for configuring the CCCD.
*
* @param[in] conn_handle The connection handle on which to configure the CCCD.
* @param[in] handle_cccd The handle of the CCCD to be configured.
* @param[in] enable Whether to enable or disable the CCCD.
*
* @return NRF_SUCCESS if the CCCD configure was successfully sent to the peer.
*/
static uint32_t cccd_configure(uint16_t conn_handle, uint16_t handle_cccd, bool enable)
{
LOG("[LBS_C]: Configuring CCCD. CCCD Handle = %d, Connection Handle = %d\r\n",
handle_cccd,conn_handle);
tx_message_t * p_msg;
uint16_t cccd_val = enable ? BLE_GATT_HVX_NOTIFICATION : 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 = 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_16(cccd_val);
p_msg->req.write_req.gattc_value[1] = MSB_16(cccd_val);
p_msg->conn_handle = conn_handle;
p_msg->type = WRITE_REQ;
tx_buffer_process();
return NRF_SUCCESS;
}
uint32_t ble_lbs_c_button_notif_enable(ble_lbs_c_t * p_ble_lbs_c)
{
VERIFY_PARAM_NOT_NULL(p_ble_lbs_c);
if (p_ble_lbs_c->conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
return cccd_configure(p_ble_lbs_c->conn_handle,
p_ble_lbs_c->peer_lbs_db.button_cccd_handle,
true);
}
uint32_t ble_lbs_led_status_send(ble_lbs_c_t * p_ble_lbs_c, uint8_t status)
{
VERIFY_PARAM_NOT_NULL(p_ble_lbs_c);
if (p_ble_lbs_c->conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
LOG("[LBS_C]: writing LED status 0x%x", status);
tx_message_t * p_msg;
p_msg = &m_tx_buffer[m_tx_insert_index++];
m_tx_insert_index &= TX_BUFFER_MASK;
p_msg->req.write_req.gattc_params.handle = p_ble_lbs_c->peer_lbs_db.led_handle;
p_msg->req.write_req.gattc_params.len = sizeof(status);
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_CMD;
p_msg->req.write_req.gattc_value[0] = status;
p_msg->conn_handle = p_ble_lbs_c->conn_handle;
p_msg->type = WRITE_REQ;
tx_buffer_process();
return NRF_SUCCESS;
}
uint32_t ble_lbs_c_handles_assign(ble_lbs_c_t * p_ble_lbs_c,
uint16_t conn_handle,
const lbs_db_t * p_peer_handles)
{
VERIFY_PARAM_NOT_NULL(p_ble_lbs_c);
p_ble_lbs_c->conn_handle = conn_handle;
if (p_peer_handles != NULL)
{
p_ble_lbs_c->peer_lbs_db = *p_peer_handles;
}
return NRF_SUCCESS;
}

View File

@ -1,191 +0,0 @@
/*
* Copyright (c) 2016 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is confidential property of Nordic Semiconductor. The use,
* copying, transfer or disclosure of such information is prohibited except by express written
* agreement with Nordic Semiconductor.
*
*/
/**@file
*
* @defgroup ble_sdk_srv_lbs_c LED Button Service Client
* @{
* @ingroup ble_sdk_srv
* @brief The LED Button Service client can be used to set a LED, and read a button state on a
* LED button service server.
*
* @details This module contains the APIs and types exposed by the LED Button Service Client
* module. These APIs and types can be used by the application to perform discovery of
* LED Button Service at the peer and interact with it.
*
* @note The application must propagate BLE stack events to this module by calling
* ble_lbs_c_on_ble_evt().
*
*/
#ifndef BLE_LBS_C_H__
#define BLE_LBS_C_H__
#include <stdint.h>
#include "ble.h"
#include "ble_db_discovery.h"
#define LBS_UUID_BASE {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, \
0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00}
#define LBS_UUID_SERVICE 0x1523
#define LBS_UUID_BUTTON_CHAR 0x1524
#define LBS_UUID_LED_CHAR 0x1525
/**@brief LBS Client event type. */
typedef enum
{
BLE_LBS_C_EVT_DISCOVERY_COMPLETE = 1, /**< Event indicating that the LED Button Service has been discovered at the peer. */
BLE_LBS_C_EVT_BUTTON_NOTIFICATION /**< Event indicating that a notification of the LED Button Button characteristic has been received from the peer. */
} ble_lbs_c_evt_type_t;
/**@brief Structure containing the Button value received from the peer. */
typedef struct
{
uint8_t button_state; /**< Button Value. */
} ble_button_t;
/**@brief Structure containing the handles related to the LED Button Service found on the peer. */
typedef struct
{
uint16_t button_cccd_handle; /**< Handle of the CCCD of the Button characteristic. */
uint16_t button_handle; /**< Handle of the Button characteristic as provided by the SoftDevice. */
uint16_t led_handle; /**< Handle of the LED characteristic as provided by the SoftDevice. */
} lbs_db_t;
/**@brief LED Button Event structure. */
typedef struct
{
ble_lbs_c_evt_type_t evt_type; /**< Type of the event. */
uint16_t conn_handle; /**< Connection handle on which the event occured.*/
union
{
ble_button_t button; /**< Button Value received. This will be filled if the evt_type is @ref BLE_LBS_C_EVT_BUTTON_NOTIFICATION. */
lbs_db_t peer_db; /**< LED Button Service related handles found on the peer device. This will be filled if the evt_type is @ref BLE_LBS_C_EVT_DISCOVERY_COMPLETE.*/
} params;
} ble_lbs_c_evt_t;
// Forward declaration of the ble_lbs_c_t type.
typedef struct ble_lbs_c_s ble_lbs_c_t;
/**@brief Event handler type.
*
* @details This is the type of the event handler that should be provided by the application
* of this module in order to receive events.
*/
typedef void (* ble_lbs_c_evt_handler_t) (ble_lbs_c_t * p_ble_lbs_c, ble_lbs_c_evt_t * p_evt);
/**@brief LED Button Client structure. */
struct ble_lbs_c_s
{
uint16_t conn_handle; /**< Connection handle as provided by the SoftDevice. */
lbs_db_t peer_lbs_db; /**< Handles related to LBS on the peer*/
ble_lbs_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the LED Button service. */
uint8_t uuid_type; /**< UUID type. */
};
/**@brief LED Button Client initialization structure. */
typedef struct
{
ble_lbs_c_evt_handler_t evt_handler; /**< Event handler to be called by the LED Button Client module whenever there is an event related to the LED Button Service. */
} ble_lbs_c_init_t;
/**@brief Function for initializing the LED Button client module.
*
* @details This function will register with the DB Discovery module. There it registers for the
* LED Button Service. Doing so will make the DB Discovery module look for the presence
* of a LED Button Service instance at the peer when a discovery is started.
*
* @param[in] p_ble_lbs_c Pointer to the LED Button client structure.
* @param[in] p_ble_lbs_c_init Pointer to the LED Button initialization structure containing the
* initialization information.
*
* @retval NRF_SUCCESS On successful initialization. Otherwise an error code. This function
* propagates the error code returned by the Database Discovery module API
* @ref ble_db_discovery_evt_register.
*/
uint32_t ble_lbs_c_init(ble_lbs_c_t * p_ble_lbs_c, ble_lbs_c_init_t * p_ble_lbs_c_init);
/**@brief Function for handling BLE events from the SoftDevice.
*
* @details This function will handle the BLE events received from the SoftDevice. If a BLE event
* is relevant to the LED Button Client module, then it uses it to update interval
* variables and, if necessary, send events to the application.
*
* @param[in] p_ble_lbs_c Pointer to the LED button client structure.
* @param[in] p_ble_evt Pointer to the BLE event.
*/
void ble_lbs_c_on_ble_evt(ble_lbs_c_t * p_ble_lbs_c, const ble_evt_t * p_ble_evt);
/**@brief Function for requesting the peer to start sending notification of the Button
* Characteristic.
*
* @details This function will enable to notification of the Button at the peer
* by writing to the CCCD of the Button Characteristic.
*
* @param[in] p_ble_lbs_c Pointer to the LED Button Client structure.
*
* @retval NRF_SUCCESS If the SoftDevice has been requested to write to the CCCD of the peer.
* Otherwise, an error code. This function propagates the error code returned
* by the SoftDevice API @ref sd_ble_gattc_write.
* NRF_ERROR_INVALID_STATE if no connection handle has been assigned (@ref ble_lbs_c_handles_assign)
* NRF_ERROR_NULL if the given parameter is NULL
*/
uint32_t ble_lbs_c_button_notif_enable(ble_lbs_c_t * p_ble_lbs_c);
/**@brief Function for handling events from the database discovery module.
*
* @details Call this function when getting a callback event from the DB discovery module. This
* function will handle an event from the database discovery module, and determine if it
* relates to the discovery of LED Button service at the peer. If so, it will call the
* application's event handler indicating that the LED Button 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_ble_lbs_c Pointer to the LED Button client structure.
* @param[in] p_evt Pointer to the event received from the database discovery module.
*/
void ble_lbs_on_db_disc_evt(ble_lbs_c_t * p_ble_lbs_c, const ble_db_discovery_evt_t * p_evt);
/**@brief Function for assigning a Handles to this instance of lbs_c.
*
* @details Call this function when a link has been established with a peer to associate this link
* to this instance of the module. This makes it possible to handle several links and
* associate each link to a particular instance of this module.
*
* @param[in] p_ble_lbs_c Pointer to the LED Button client structure instance to associate.
* @param[in] conn_handle Connection handle to associate with the given LED Button Client Instance.
* @param[in] p_peer_handles LED Button Service handles found on the peer (from @ref BLE_LBS_C_EVT_DISCOVERY_COMPLETE event).
*
*/
uint32_t ble_lbs_c_handles_assign(ble_lbs_c_t * p_ble_lbs_c,
uint16_t conn_handle,
const lbs_db_t * p_peer_handles);
/**@brief Function for writing the LED status to the connected server.
*
* @param[in] p_ble_lbs_c Pointer to the LED Button client structure.
* @param[in] status LED status to send.
*
* @retval NRF_SUCCESS If the staus was sent successfully. Otherwise, an error code is returned.
*/
uint32_t ble_lbs_led_status_send(ble_lbs_c_t * p_ble_lbs_c, uint8_t status);
#endif // BLE_LBS_C_H__
/** @} */

View File

@ -1,214 +0,0 @@
/* 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.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#include "ble_lls.h"
#include <string.h>
#include "ble_hci.h"
#include "ble_srv_common.h"
/**@brief Function for handling the Connect event.
*
* @param[in] p_lls Link Loss Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_connect(ble_lls_t * p_lls, ble_evt_t * p_ble_evt)
{
// Link reconnected, notify application with a no_alert event
ble_lls_evt_t evt;
p_lls->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
evt.evt_type = BLE_LLS_EVT_LINK_LOSS_ALERT;
evt.params.alert_level = BLE_CHAR_ALERT_LEVEL_NO_ALERT;
p_lls->evt_handler(p_lls, &evt);
}
/**@brief Function for handling the Disconnect event.
*
* @param[in] p_lls Link Loss Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_disconnect(ble_lls_t * p_lls, ble_evt_t * p_ble_evt)
{
uint8_t reason = p_ble_evt->evt.gap_evt.params.disconnected.reason;
if (reason == BLE_HCI_CONNECTION_TIMEOUT)
{
// Link loss detected, notify application
uint32_t err_code;
ble_lls_evt_t evt;
evt.evt_type = BLE_LLS_EVT_LINK_LOSS_ALERT;
err_code = ble_lls_alert_level_get(p_lls, &evt.params.alert_level);
if (err_code == NRF_SUCCESS)
{
p_lls->evt_handler(p_lls, &evt);
}
else
{
if (p_lls->error_handler != NULL)
{
p_lls->error_handler(err_code);
}
}
}
}
/**@brief Function for handling the Authentication Status event.
*
* @param[in] p_lls Link Loss Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_auth_status(ble_lls_t * p_lls, ble_evt_t * p_ble_evt)
{
if (p_ble_evt->evt.gap_evt.params.auth_status.auth_status == BLE_GAP_SEC_STATUS_SUCCESS)
{
ble_lls_evt_t evt;
evt.evt_type = BLE_LLS_EVT_LINK_LOSS_ALERT;
evt.params.alert_level = BLE_CHAR_ALERT_LEVEL_NO_ALERT;
p_lls->evt_handler(p_lls, &evt);
}
}
void ble_lls_on_ble_evt(ble_lls_t * p_lls, ble_evt_t * p_ble_evt)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_lls, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_lls, p_ble_evt);
break;
case BLE_GAP_EVT_AUTH_STATUS:
on_auth_status(p_lls, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
/**@brief Function for adding Alert Level characteristics.
*
* @param[in] p_lls Link Loss Service structure.
* @param[in] p_lls_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t alert_level_char_add(ble_lls_t * p_lls, const ble_lls_init_t * p_lls_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
uint8_t initial_alert_level;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.char_props.write = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_ALERT_LEVEL_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
attr_md.read_perm = p_lls_init->lls_attr_md.read_perm;
attr_md.write_perm = p_lls_init->lls_attr_md.write_perm;
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 0;
memset(&attr_char_value, 0, sizeof(attr_char_value));
initial_alert_level = p_lls_init->initial_alert_level;
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof (uint8_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = sizeof (uint8_t);
attr_char_value.p_value = &initial_alert_level;
return sd_ble_gatts_characteristic_add(p_lls->service_handle,
&char_md,
&attr_char_value,
&p_lls->alert_level_handles);
}
uint32_t ble_lls_init(ble_lls_t * p_lls, const ble_lls_init_t * p_lls_init)
{
uint32_t err_code;
ble_uuid_t ble_uuid;
// Initialize service structure
if (p_lls_init->evt_handler == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
p_lls->evt_handler = p_lls_init->evt_handler;
p_lls->error_handler = p_lls_init->error_handler;
// Add service
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_LINK_LOSS_SERVICE);
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
&ble_uuid,
&p_lls->service_handle);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add alert level characteristic
return alert_level_char_add(p_lls, p_lls_init);
}
uint32_t ble_lls_alert_level_get(ble_lls_t * p_lls, uint8_t * p_alert_level)
{
ble_gatts_value_t gatts_value;
// Initialize value struct.
memset(&gatts_value, 0, sizeof(gatts_value));
gatts_value.len = sizeof(uint8_t);
gatts_value.offset = 0;
gatts_value.p_value = p_alert_level;
return sd_ble_gatts_value_get(p_lls->conn_handle,
p_lls->alert_level_handles.value_handle,
&gatts_value);
}

View File

@ -1,116 +0,0 @@
/* 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_lls Link Loss Service
* @{
* @ingroup ble_sdk_srv
* @brief Link Loss Service module.
*
* @details This module implements the Link Loss Service with the Alert Level characteristic.
* During initialization it adds the Link Loss Service and Alert Level characteristic
* to the BLE stack database.
*
* The application must supply an event handler for receiving Link Loss Service
* events. Using this handler, the service will notify the application when the
* link has been lost, and which Alert Level has been set.
*
* The service also provides a function for letting the application poll the current
* value of the Alert Level characteristic.
*
* @note The application must propagate BLE stack events to the Link Loss Service
* module by calling ble_lls_on_ble_evt() from the @ref softdevice_handler callback.
*
* @note Attention!
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_LLS_H__
#define BLE_LLS_H__
#include <stdint.h>
#include "ble.h"
#include "ble_srv_common.h"
/**@brief Link Loss Service event type. */
typedef enum
{
BLE_LLS_EVT_LINK_LOSS_ALERT /**< Alert Level Updated event. */
} ble_lls_evt_type_t;
/**@brief Link Loss Service event. */
typedef struct
{
ble_lls_evt_type_t evt_type; /**< Type of event. */
union
{
uint8_t alert_level; /**< New Alert Level value. */
} params;
} ble_lls_evt_t;
// Forward declaration of the ble_lls_t type.
typedef struct ble_lls_s ble_lls_t;
/**@brief Link Loss Service event handler type. */
typedef void (*ble_lls_evt_handler_t) (ble_lls_t * p_lls, ble_lls_evt_t * p_evt);
/**@brief Link Loss Service init structure. This contains all options and data needed for initialization of the service. */
typedef struct
{
ble_lls_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Link Loss Service. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
uint8_t initial_alert_level; /**< Initial value of the Alert Level characteristic. */
ble_srv_security_mode_t lls_attr_md; /**< Initial Security Setting for Link Loss Service Characteristics. */
} ble_lls_init_t;
/**@brief Link Loss Service structure. This contains various status information for the service. */
struct ble_lls_s
{
ble_lls_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Link Loss Service. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
uint16_t service_handle; /**< Handle of Link Loss Service (as provided by the BLE stack). */
ble_gatts_char_handles_t alert_level_handles; /**< Handles related to the Alert Level characteristic. */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
};
/**@brief Function for initializing the Link Loss Service.
*
* @param[out] p_lls Link Loss Service structure. This structure will have to be supplied by
* the application. It will be initialized by this function, and will later
* be used to identify this particular service instance.
* @param[in] p_lls_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
*/
uint32_t ble_lls_init(ble_lls_t * p_lls, const ble_lls_init_t * p_lls_init);
/**@brief Function for handling the Application's BLE Stack events.
*
* @details Handles all events from the BLE stack of interest to the Link Loss Service.
*
* @param[in] p_lls Link Loss Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_lls_on_ble_evt(ble_lls_t * p_lls, ble_evt_t * p_ble_evt);
/**@brief Function for getting current value of the Alert Level characteristic.
*
* @param[in] p_lls Link Loss Service structure.
* @param[out] p_alert_level Current Alert Level value.
*/
uint32_t ble_lls_alert_level_get(ble_lls_t * p_lls, uint8_t * p_alert_level);
#endif // BLE_LLS_H__
/** @} */

View File

@ -1,295 +0,0 @@
/* 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 "ble_nus.h"
#include "ble_srv_common.h"
#include "sdk_common.h"
#define BLE_UUID_NUS_TX_CHARACTERISTIC 0x0002 /**< The UUID of the TX Characteristic. */
#define BLE_UUID_NUS_RX_CHARACTERISTIC 0x0003 /**< The UUID of the RX Characteristic. */
#define BLE_NUS_MAX_RX_CHAR_LEN BLE_NUS_MAX_DATA_LEN /**< Maximum length of the RX Characteristic (in bytes). */
#define BLE_NUS_MAX_TX_CHAR_LEN BLE_NUS_MAX_DATA_LEN /**< Maximum length of the TX Characteristic (in bytes). */
#define NUS_BASE_UUID {{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}} /**< Used vendor specific UUID. */
/**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the S110 SoftDevice.
*
* @param[in] p_nus Nordic UART Service structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_connect(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
{
p_nus->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}
/**@brief Function for handling the @ref BLE_GAP_EVT_DISCONNECTED event from the S110 SoftDevice.
*
* @param[in] p_nus Nordic UART Service structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_disconnect(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
{
UNUSED_PARAMETER(p_ble_evt);
p_nus->conn_handle = BLE_CONN_HANDLE_INVALID;
}
/**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the S110 SoftDevice.
*
* @param[in] p_nus Nordic UART Service structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_write(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
{
ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
if (
(p_evt_write->handle == p_nus->rx_handles.cccd_handle)
&&
(p_evt_write->len == 2)
)
{
if (ble_srv_is_notification_enabled(p_evt_write->data))
{
p_nus->is_notification_enabled = true;
}
else
{
p_nus->is_notification_enabled = false;
}
}
else if (
(p_evt_write->handle == p_nus->tx_handles.value_handle)
&&
(p_nus->data_handler != NULL)
)
{
p_nus->data_handler(p_nus, p_evt_write->data, p_evt_write->len);
}
else
{
// Do Nothing. This event is not relevant for this service.
}
}
/**@brief Function for adding RX characteristic.
*
* @param[in] p_nus Nordic UART Service structure.
* @param[in] p_nus_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t rx_char_add(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
{
/**@snippet [Adding proprietary characteristic to S110 SoftDevice] */
ble_gatts_char_md_t char_md;
ble_gatts_attr_md_t cccd_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
memset(&cccd_md, 0, sizeof(cccd_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.notify = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = &cccd_md;
char_md.p_sccd_md = NULL;
ble_uuid.type = p_nus->uuid_type;
ble_uuid.uuid = BLE_UUID_NUS_RX_CHARACTERISTIC;
memset(&attr_md, 0, sizeof(attr_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof(uint8_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = BLE_NUS_MAX_RX_CHAR_LEN;
return sd_ble_gatts_characteristic_add(p_nus->service_handle,
&char_md,
&attr_char_value,
&p_nus->rx_handles);
/**@snippet [Adding proprietary characteristic to S110 SoftDevice] */
}
/**@brief Function for adding TX characteristic.
*
* @param[in] p_nus Nordic UART Service structure.
* @param[in] p_nus_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t tx_char_add(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.write = 1;
char_md.char_props.write_wo_resp = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
ble_uuid.type = p_nus->uuid_type;
ble_uuid.uuid = BLE_UUID_NUS_TX_CHARACTERISTIC;
memset(&attr_md, 0, sizeof(attr_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = 1;
attr_char_value.init_offs = 0;
attr_char_value.max_len = BLE_NUS_MAX_TX_CHAR_LEN;
return sd_ble_gatts_characteristic_add(p_nus->service_handle,
&char_md,
&attr_char_value,
&p_nus->tx_handles);
}
void ble_nus_on_ble_evt(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
{
if ((p_nus == NULL) || (p_ble_evt == NULL))
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_nus, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_nus, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_nus, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
uint32_t ble_nus_init(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
{
uint32_t err_code;
ble_uuid_t ble_uuid;
ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
VERIFY_PARAM_NOT_NULL(p_nus);
VERIFY_PARAM_NOT_NULL(p_nus_init);
// Initialize the service structure.
p_nus->conn_handle = BLE_CONN_HANDLE_INVALID;
p_nus->data_handler = p_nus_init->data_handler;
p_nus->is_notification_enabled = false;
/**@snippet [Adding proprietary Service to S110 SoftDevice] */
// Add a custom base UUID.
err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);
VERIFY_SUCCESS(err_code);
ble_uuid.type = p_nus->uuid_type;
ble_uuid.uuid = BLE_UUID_NUS_SERVICE;
// Add the service.
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
&ble_uuid,
&p_nus->service_handle);
/**@snippet [Adding proprietary Service to S110 SoftDevice] */
VERIFY_SUCCESS(err_code);
// Add the RX Characteristic.
err_code = rx_char_add(p_nus, p_nus_init);
VERIFY_SUCCESS(err_code);
// Add the TX Characteristic.
err_code = tx_char_add(p_nus, p_nus_init);
VERIFY_SUCCESS(err_code);
return NRF_SUCCESS;
}
uint32_t ble_nus_string_send(ble_nus_t * p_nus, uint8_t * p_string, uint16_t length)
{
ble_gatts_hvx_params_t hvx_params;
VERIFY_PARAM_NOT_NULL(p_nus);
if ((p_nus->conn_handle == BLE_CONN_HANDLE_INVALID) || (!p_nus->is_notification_enabled))
{
return NRF_ERROR_INVALID_STATE;
}
if (length > BLE_NUS_MAX_DATA_LEN)
{
return NRF_ERROR_INVALID_PARAM;
}
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_nus->rx_handles.value_handle;
hvx_params.p_data = p_string;
hvx_params.p_len = &length;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
return sd_ble_gatts_hvx(p_nus->conn_handle, &hvx_params);
}

View File

@ -1,114 +0,0 @@
/* 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.
*
*/
/**@file
*
* @defgroup ble_sdk_srv_nus Nordic UART Service
* @{
* @ingroup ble_sdk_srv
* @brief Nordic UART Service implementation.
*
* @details The Nordic UART Service is a simple GATT-based service with TX and RX characteristics.
* Data received from the peer is passed to the application, and the data received
* from the application of this service is sent to the peer as Handle Value
* Notifications. This module demonstrates how to implement a custom GATT-based
* service and characteristics using the SoftDevice. The service
* is used by the application to send and receive ASCII text strings to and from the
* peer.
*
* @note The application must propagate SoftDevice events to the Nordic UART Service module
* by calling the ble_nus_on_ble_evt() function from the ble_stack_handler callback.
*/
#ifndef BLE_NUS_H__
#define BLE_NUS_H__
#include "ble.h"
#include "ble_srv_common.h"
#include <stdint.h>
#include <stdbool.h>
#define BLE_UUID_NUS_SERVICE 0x0001 /**< The UUID of the Nordic UART Service. */
#define BLE_NUS_MAX_DATA_LEN (GATT_MTU_SIZE_DEFAULT - 3) /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
/* Forward declaration of the ble_nus_t type. */
typedef struct ble_nus_s ble_nus_t;
/**@brief Nordic UART Service event handler type. */
typedef void (*ble_nus_data_handler_t) (ble_nus_t * p_nus, uint8_t * p_data, uint16_t length);
/**@brief Nordic UART Service initialization structure.
*
* @details This structure contains the initialization information for the service. The application
* must fill this structure and pass it to the service using the @ref ble_nus_init
* function.
*/
typedef struct
{
ble_nus_data_handler_t data_handler; /**< Event handler to be called for handling received data. */
} ble_nus_init_t;
/**@brief Nordic UART Service structure.
*
* @details This structure contains status information related to the service.
*/
struct ble_nus_s
{
uint8_t uuid_type; /**< UUID type for Nordic UART Service Base UUID. */
uint16_t service_handle; /**< Handle of Nordic UART Service (as provided by the SoftDevice). */
ble_gatts_char_handles_t tx_handles; /**< Handles related to the TX characteristic (as provided by the SoftDevice). */
ble_gatts_char_handles_t rx_handles; /**< Handles related to the RX characteristic (as provided by the SoftDevice). */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the SoftDevice). BLE_CONN_HANDLE_INVALID if not in a connection. */
bool is_notification_enabled; /**< Variable to indicate if the peer has enabled notification of the RX characteristic.*/
ble_nus_data_handler_t data_handler; /**< Event handler to be called for handling received data. */
};
/**@brief Function for initializing the Nordic UART Service.
*
* @param[out] p_nus Nordic UART Service structure. This structure must be supplied
* by the application. It is initialized by this function and will
* later be used to identify this particular service instance.
* @param[in] p_nus_init Information needed to initialize the service.
*
* @retval NRF_SUCCESS If the service was successfully initialized. Otherwise, an error code is returned.
* @retval NRF_ERROR_NULL If either of the pointers p_nus or p_nus_init is NULL.
*/
uint32_t ble_nus_init(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init);
/**@brief Function for handling the Nordic UART Service's BLE events.
*
* @details The Nordic UART Service expects the application to call this function each time an
* event is received from the SoftDevice. This function processes the event if it
* is relevant and calls the Nordic UART Service event handler of the
* application if necessary.
*
* @param[in] p_nus Nordic UART Service structure.
* @param[in] p_ble_evt Event received from the SoftDevice.
*/
void ble_nus_on_ble_evt(ble_nus_t * p_nus, ble_evt_t * p_ble_evt);
/**@brief Function for sending a string to the peer.
*
* @details This function sends the input string as an RX characteristic notification to the
* peer.
*
* @param[in] p_nus Pointer to the Nordic UART Service structure.
* @param[in] p_string String to be sent.
* @param[in] length Length of the string.
*
* @retval NRF_SUCCESS If the string was sent successfully. Otherwise, an error code is returned.
*/
uint32_t ble_nus_string_send(ble_nus_t * p_nus, uint8_t * p_string, uint16_t length);
#endif // BLE_NUS_H__
/** @} */

View File

@ -1,212 +0,0 @@
#include <stdlib.h> // definition of NULL
#include "ble.h"
#include "ble_nus_c.h"
#include "ble_gattc.h"
#include "ble_srv_common.h"
#include "app_error.h"
#include "sdk_common.h"
void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt)
{
ble_nus_c_evt_t nus_c_evt;
memset(&nus_c_evt,0,sizeof(ble_nus_c_evt_t));
ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;
// Check if the NUS was discovered.
if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_NUS_SERVICE &&
p_evt->params.discovered_db.srv_uuid.type == p_ble_nus_c->uuid_type)
{
uint32_t i;
for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
switch (p_chars[i].characteristic.uuid.uuid)
{
case BLE_UUID_NUS_TX_CHARACTERISTIC:
nus_c_evt.handles.nus_tx_handle = p_chars[i].characteristic.handle_value;
break;
case BLE_UUID_NUS_RX_CHARACTERISTIC:
nus_c_evt.handles.nus_rx_handle = p_chars[i].characteristic.handle_value;
nus_c_evt.handles.nus_rx_cccd_handle = p_chars[i].cccd_handle;
break;
default:
break;
}
}
if (p_ble_nus_c->evt_handler != NULL)
{
nus_c_evt.conn_handle = p_evt->conn_handle;
nus_c_evt.evt_type = BLE_NUS_C_EVT_DISCOVERY_COMPLETE;
p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
}
}
}
/**@brief Function for handling Handle Value Notification received from the SoftDevice.
*
* @details This function will uses the Handle Value Notification received from the SoftDevice
* and checks if it is a notification of the NUS RX characteristic from the peer. If
* it is, this function will decode the data and send it to the
* application.
*
* @param[in] p_ble_nus_c Pointer to the NUS Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_hvx(ble_nus_c_t * p_ble_nus_c, const ble_evt_t * p_ble_evt)
{
// HVX can only occur from client sending.
if ( (p_ble_nus_c->handles.nus_rx_handle != BLE_GATT_HANDLE_INVALID)
&& (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_nus_c->handles.nus_rx_handle)
&& (p_ble_nus_c->evt_handler != NULL)
)
{
ble_nus_c_evt_t ble_nus_c_evt;
ble_nus_c_evt.evt_type = BLE_NUS_C_EVT_NUS_RX_EVT;
ble_nus_c_evt.p_data = (uint8_t *)p_ble_evt->evt.gattc_evt.params.hvx.data;
ble_nus_c_evt.data_len = p_ble_evt->evt.gattc_evt.params.hvx.len;
p_ble_nus_c->evt_handler(p_ble_nus_c, &ble_nus_c_evt);
}
}
uint32_t ble_nus_c_init(ble_nus_c_t * p_ble_nus_c, ble_nus_c_init_t * p_ble_nus_c_init)
{
uint32_t err_code;
ble_uuid_t uart_uuid;
ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
VERIFY_PARAM_NOT_NULL(p_ble_nus_c_init);
err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_ble_nus_c->uuid_type);
VERIFY_SUCCESS(err_code);
uart_uuid.type = p_ble_nus_c->uuid_type;
uart_uuid.uuid = BLE_UUID_NUS_SERVICE;
p_ble_nus_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ble_nus_c->evt_handler = p_ble_nus_c_init->evt_handler;
p_ble_nus_c->handles.nus_rx_handle = BLE_GATT_HANDLE_INVALID;
p_ble_nus_c->handles.nus_tx_handle = BLE_GATT_HANDLE_INVALID;
return ble_db_discovery_evt_register(&uart_uuid);
}
void ble_nus_c_on_ble_evt(ble_nus_c_t * p_ble_nus_c, const ble_evt_t * p_ble_evt)
{
if ((p_ble_nus_c == NULL) || (p_ble_evt == NULL))
{
return;
}
if ( (p_ble_nus_c->conn_handle != BLE_CONN_HANDLE_INVALID)
&&(p_ble_nus_c->conn_handle != p_ble_evt->evt.gap_evt.conn_handle)
)
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_GATTC_EVT_HVX:
on_hvx(p_ble_nus_c, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
if (p_ble_evt->evt.gap_evt.conn_handle == p_ble_nus_c->conn_handle
&& p_ble_nus_c->evt_handler != NULL)
{
ble_nus_c_evt_t nus_c_evt;
nus_c_evt.evt_type = BLE_NUS_C_EVT_DISCONNECTED;
p_ble_nus_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
}
break;
}
}
/**@brief Function for creating a message for writing to the CCCD.
*/
static uint32_t cccd_configure(uint16_t conn_handle, uint16_t cccd_handle, bool enable)
{
uint8_t buf[BLE_CCCD_VALUE_LEN];
buf[0] = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
buf[1] = 0;
const ble_gattc_write_params_t write_params = {
.write_op = BLE_GATT_OP_WRITE_REQ,
.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
.handle = cccd_handle,
.offset = 0,
.len = sizeof(buf),
.p_value = buf
};
return sd_ble_gattc_write(conn_handle, &write_params);
}
uint32_t ble_nus_c_rx_notif_enable(ble_nus_c_t * p_ble_nus_c)
{
VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
if ( (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
||(p_ble_nus_c->handles.nus_rx_cccd_handle == BLE_GATT_HANDLE_INVALID)
)
{
return NRF_ERROR_INVALID_STATE;
}
return cccd_configure(p_ble_nus_c->conn_handle,p_ble_nus_c->handles.nus_rx_cccd_handle, true);
}
uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length)
{
VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
if (length > BLE_NUS_MAX_DATA_LEN)
{
return NRF_ERROR_INVALID_PARAM;
}
if ( p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
const ble_gattc_write_params_t write_params = {
.write_op = BLE_GATT_OP_WRITE_CMD,
.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
.handle = p_ble_nus_c->handles.nus_tx_handle,
.offset = 0,
.len = length,
.p_value = p_string
};
return sd_ble_gattc_write(p_ble_nus_c->conn_handle, &write_params);
}
uint32_t ble_nus_c_handles_assign(ble_nus_c_t * p_ble_nus,
const uint16_t conn_handle,
const ble_nus_c_handles_t * p_peer_handles)
{
VERIFY_PARAM_NOT_NULL(p_ble_nus);
p_ble_nus->conn_handle = conn_handle;
if (p_peer_handles != NULL)
{
p_ble_nus->handles.nus_rx_cccd_handle = p_peer_handles->nus_rx_cccd_handle;
p_ble_nus->handles.nus_rx_handle = p_peer_handles->nus_rx_handle;
p_ble_nus->handles.nus_tx_handle = p_peer_handles->nus_tx_handle;
}
return NRF_SUCCESS;
}

View File

@ -1,192 +0,0 @@
/*
* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is confidential property of Nordic Semiconductor. The use,
* copying, transfer or disclosure of such information is prohibited except by express written
* agreement with Nordic Semiconductor.
*
*/
/**@file
*
* @defgroup ble_sdk_srv_nus_c Nordic UART Service Client
* @{
* @ingroup ble_sdk_srv
* @brief Nordic UART Service Client module.
*
* @details This module contains the APIs and types exposed by the Nordic UART Service Client
* module. These APIs and types can be used by the application to perform discovery of
* the Nordic UART Service at the peer and interact with it.
*
* @note The application must propagate BLE stack events to this module by calling
* ble_nus_c_on_ble_evt().
*
*/
#ifndef BLE_NUS_C_H__
#define BLE_NUS_C_H__
#include <stdint.h>
#include <stdbool.h>
#include "ble.h"
#include "ble_gatt.h"
#include "ble_db_discovery.h"
#define NUS_BASE_UUID {{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}} /**< Used vendor specific UUID. */
#define BLE_UUID_NUS_SERVICE 0x0001 /**< The UUID of the Nordic UART Service. */
#define BLE_UUID_NUS_TX_CHARACTERISTIC 0x0002 /**< The UUID of the TX Characteristic. */
#define BLE_UUID_NUS_RX_CHARACTERISTIC 0x0003 /**< The UUID of the RX Characteristic. */
#define BLE_NUS_MAX_DATA_LEN (GATT_MTU_SIZE_DEFAULT - 3) /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
/**@brief NUS Client event type. */
typedef enum
{
BLE_NUS_C_EVT_DISCOVERY_COMPLETE = 1, /**< Event indicating that the NUS service and its characteristics was found. */
BLE_NUS_C_EVT_NUS_RX_EVT, /**< Event indicating that the central has received something from a peer. */
BLE_NUS_C_EVT_DISCONNECTED /**< Event indicating that the NUS server has disconnected. */
} ble_nus_c_evt_type_t;
/**@brief Handles on the connected peer device needed to interact with it.
*/
typedef struct {
uint16_t nus_rx_handle; /**< Handle of the NUS RX characteristic as provided by a discovery. */
uint16_t nus_rx_cccd_handle; /**< Handle of the CCCD of the NUS RX characteristic as provided by a discovery. */
uint16_t nus_tx_handle; /**< Handle of the NUS TX characteristic as provided by a discovery. */
} ble_nus_c_handles_t;
/**@brief Structure containing the NUS event data received from the peer. */
typedef struct {
ble_nus_c_evt_type_t evt_type;
uint16_t conn_handle;
uint8_t * p_data;
uint8_t data_len;
ble_nus_c_handles_t handles; /**< Handles on which the Nordic Uart service characteristics was discovered on the peer device. This will be filled if the evt_type is @ref BLE_NUS_C_EVT_DISCOVERY_COMPLETE.*/
} ble_nus_c_evt_t;
// Forward declaration of the ble_nus_t type.
typedef struct ble_nus_c_s ble_nus_c_t;
/**@brief Event handler type.
*
* @details This is the type of the event handler that should be provided by the application
* of this module to receive events.
*/
typedef void (* ble_nus_c_evt_handler_t)(ble_nus_c_t * p_ble_nus_c, const ble_nus_c_evt_t * p_evt);
/**@brief NUS Client structure.
*/
struct ble_nus_c_s
{
uint8_t uuid_type; /**< UUID type. */
uint16_t conn_handle; /**< Handle of the current connection. Set with @ref ble_nus_c_handles_assign when connected. */
ble_nus_c_handles_t handles; /**< Handles on the connected peer device needed to interact with it. */
ble_nus_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the NUS. */
};
/**@brief NUS Client initialization structure.
*/
typedef struct {
ble_nus_c_evt_handler_t evt_handler;
} ble_nus_c_init_t;
/**@brief Function for initializing the Nordic UART client module.
*
* @details This function registers with the Database Discovery module
* for the NUS. Doing so will make the Database Discovery
* module look for the presence of a NUS instance at the peer when a
* discovery is started.
*
* @param[in] p_ble_nus_c Pointer to the NUS client structure.
* @param[in] p_ble_nus_c_init Pointer to the NUS initialization structure containing the
* initialization information.
*
* @retval NRF_SUCCESS If the module was initialized successfully. Otherwise, an error
* code is returned. This function
* propagates the error code returned by the Database Discovery module API
* @ref ble_db_discovery_evt_register.
*/
uint32_t ble_nus_c_init(ble_nus_c_t * p_ble_nus_c, ble_nus_c_init_t * p_ble_nus_c_init);
/**@brief Function for handling events from the database discovery module.
*
* @details This function will handle an event from the database discovery module, and determine
* if it relates to the discovery of NUS at the peer. If so, it will
* call the application's event handler indicating that NUS 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_ble_nus_c Pointer to the NUS client structure.
* @param[in] p_evt Pointer to the event received from the database discovery module.
*/
void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt);
/**@brief Function for handling BLE events from the SoftDevice.
*
* @details This function handles the BLE events received from the SoftDevice. If a BLE
* event is relevant to the NUS module, it is used to update
* internal variables and, if necessary, send events to the application.
*
* @param[in] p_ble_nus_c Pointer to the NUS client structure.
* @param[in] p_ble_evt Pointer to the BLE event.
*/
void ble_nus_c_on_ble_evt(ble_nus_c_t * p_ble_nus_c, const ble_evt_t * p_ble_evt);
/**@brief Function for requesting the peer to start sending notification of RX characteristic.
*
* @details This function enables notifications of the NUS RX characteristic at the peer
* by writing to the CCCD of the NUS RX characteristic.
*
* @param p_ble_nus_c Pointer to the NUS client structure.
*
* @retval NRF_SUCCESS If the SoftDevice has been requested to write to the CCCD of the peer.
* Otherwise, an error code is returned. This function propagates the error
* code returned by the SoftDevice API @ref sd_ble_gattc_write.
*/
uint32_t ble_nus_c_rx_notif_enable(ble_nus_c_t * p_ble_nus_c);
/**@brief Function for sending a string to the server.
*
* @details This function writes the TX characteristic of the server.
*
* @param[in] p_ble_nus_c Pointer to the NUS client structure.
* @param[in] p_string String to be sent.
* @param[in] length Length of the string.
*
* @retval NRF_SUCCESS If the string was sent successfully. Otherwise, an error code is returned.
*/
uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length);
/**@brief Function for assigning handles to a this instance of nus_c.
*
* @details Call this function when a link has been established with a peer to
* associate this link to this instance of the module. This makes it
* possible to handle several link and associate each link to a particular
* instance of this module. The connection handle and attribute handles will be
* provided from the discovery event @ref BLE_NUS_C_EVT_DISCOVERY_COMPLETE.
*
* @param[in] p_ble_nus_c Pointer to the NUS client structure instance to associate with these
* handles.
* @param[in] conn_handle Connection handle to associated with the given NUS Instance.
* @param[in] p_peer_handles Attribute handles on the NUS server that you want this NUS client to
* interact with.
*
* @retval NRF_SUCCESS If the operation was successful.
* @retval NRF_ERROR_NULL If a p_nus was a NULL pointer.
*/
uint32_t ble_nus_c_handles_assign(ble_nus_c_t * p_ble_nus_c, const uint16_t conn_handle, const ble_nus_c_handles_t * p_peer_handles);
#endif // BLE_NUS_C_H__
/** @} */

View File

@ -1,385 +0,0 @@
/* 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.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#include "ble_rscs.h"
#include <string.h>
#include "nordic_common.h"
#include "ble_l2cap.h"
#include "ble_srv_common.h"
#include "app_util.h"
#define OPCODE_LENGTH 1 /**< Length of opcode inside Running Speed and Cadence Measurement packet. */
#define HANDLE_LENGTH 2 /**< Length of handle inside Running Speed and Cadence Measurement packet. */
#define MAX_RSCM_LEN (BLE_L2CAP_MTU_DEF - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Running Speed and Cadence Measurement. */
// Running Speed and Cadence Measurement flag bits
#define RSC_MEAS_FLAG_INSTANT_STRIDE_LEN_PRESENT (0x01 << 0) /**< Instantaneous Stride Length Present flag bit. */
#define RSC_MEAS_FLAG_TOTAL_DISTANCE_PRESENT (0x01 << 1) /**< Total Distance Present flag bit. */
#define RSC_MEAS_FLAG_WALKING_OR_RUNNING_BIT (0x01 << 2) /**< Walking or Running Status flag bit. */
/**@brief Function for handling the Connect event.
*
* @param[in] p_rscs Running Speed and Cadence Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_connect(ble_rscs_t * p_rscs, ble_evt_t * p_ble_evt)
{
p_rscs->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}
/**@brief Function for handling the Disconnect event.
*
* @param[in] p_rscs Running Speed and Cadence Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_disconnect(ble_rscs_t * p_rscs, ble_evt_t * p_ble_evt)
{
UNUSED_PARAMETER(p_ble_evt);
p_rscs->conn_handle = BLE_CONN_HANDLE_INVALID;
}
/**@brief Function for handling the write events to the RSCS Measurement characteristic.
*
* @param[in] p_rscs Running Speed and Cadence Service structure.
* @param[in] p_evt_write Write event received from the BLE stack.
*/
static void on_meas_cccd_write(ble_rscs_t * p_rscs, ble_gatts_evt_write_t * p_evt_write)
{
if (p_evt_write->len == 2)
{
// CCCD written, update notification state
if (p_rscs->evt_handler != NULL)
{
ble_rscs_evt_t evt;
if (ble_srv_is_notification_enabled(p_evt_write->data))
{
evt.evt_type = BLE_RSCS_EVT_NOTIFICATION_ENABLED;
}
else
{
evt.evt_type = BLE_RSCS_EVT_NOTIFICATION_DISABLED;
}
p_rscs->evt_handler(p_rscs, &evt);
}
}
}
/**@brief Function for handling the Write event.
*
* @param[in] p_rscs Running Speed and Cadence Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_write(ble_rscs_t * p_rscs, ble_evt_t * p_ble_evt)
{
ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
if (p_evt_write->handle == p_rscs->meas_handles.cccd_handle)
{
on_meas_cccd_write(p_rscs, p_evt_write);
}
}
void ble_rscs_on_ble_evt(ble_rscs_t * p_rscs, ble_evt_t * p_ble_evt)
{
if (p_rscs == NULL || p_ble_evt == NULL)
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_rscs, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_rscs, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_rscs, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
/**@brief Function for encoding a RSCS Measurement.
*
* @param[in] p_rscs Running Speed and Cadence Service structure.
* @param[in] p_rsc_measurement Measurement to be encoded.
* @param[out] p_encoded_buffer Buffer where the encoded data will be written.
*
* @return Size of encoded data.
*/
static uint8_t rsc_measurement_encode(const ble_rscs_t * p_rscs,
const ble_rscs_meas_t * p_rsc_measurement,
uint8_t * p_encoded_buffer)
{
uint8_t flags = 0;
uint8_t len = 1;
// Instantaneous speed field
len += uint16_encode(p_rsc_measurement->inst_speed, &p_encoded_buffer[len]);
// Instantaneous cadence field
p_encoded_buffer[len++] = p_rsc_measurement->inst_cadence;
// Instantaneous stride length field
if (p_rscs->feature & BLE_RSCS_FEATURE_INSTANT_STRIDE_LEN_BIT)
{
if (p_rsc_measurement->is_inst_stride_len_present)
{
flags |= RSC_MEAS_FLAG_INSTANT_STRIDE_LEN_PRESENT;
len += uint16_encode(p_rsc_measurement->inst_stride_length,
&p_encoded_buffer[len]);
}
}
// Total distance field
if (p_rscs->feature & BLE_RSCS_FEATURE_TOTAL_DISTANCE_BIT)
{
if (p_rsc_measurement->is_total_distance_present)
{
flags |= RSC_MEAS_FLAG_TOTAL_DISTANCE_PRESENT;
len += uint32_encode(p_rsc_measurement->total_distance, &p_encoded_buffer[len]);
}
}
// Flags field
if (p_rscs->feature & BLE_RSCS_FEATURE_WALKING_OR_RUNNING_STATUS_BIT)
{
if (p_rsc_measurement->is_running)
{
flags |= RSC_MEAS_FLAG_WALKING_OR_RUNNING_BIT;
}
}
p_encoded_buffer[0] = flags;
return len;
}
/**@brief Function for adding RSC Measurement characteristics.
*
* @param[in] p_rscs Running Speed and Cadence Service structure.
* @param[in] p_rscs_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t rsc_measurement_char_add(ble_rscs_t * p_rscs, const ble_rscs_init_t * p_rscs_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_md_t cccd_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
uint8_t encoded_rcm[MAX_RSCM_LEN];
memset(&cccd_md, 0, sizeof(cccd_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
cccd_md.write_perm = p_rscs_init->rsc_meas_attr_md.cccd_write_perm;
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.notify = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = &cccd_md;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_RSC_MEASUREMENT_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
attr_md.read_perm = p_rscs_init->rsc_meas_attr_md.read_perm;
attr_md.write_perm = p_rscs_init->rsc_meas_attr_md.write_perm;
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = rsc_measurement_encode(p_rscs, &p_rscs_init->initial_rcm, encoded_rcm);
attr_char_value.init_offs = 0;
attr_char_value.max_len = MAX_RSCM_LEN;
attr_char_value.p_value = encoded_rcm;
return sd_ble_gatts_characteristic_add(p_rscs->service_handle,
&char_md,
&attr_char_value,
&p_rscs->meas_handles);
}
/**@brief Function for adding RSC Feature characteristics.
*
* @param[in] p_rscs Running Speed and Cadence Service structure.
* @param[in] p_rscs_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t rsc_feature_char_add(ble_rscs_t * p_rscs, const ble_rscs_init_t * p_rscs_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
uint16_t init_value_feature;
uint8_t init_value_encoded[2];
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_RSC_FEATURE_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
attr_md.read_perm = p_rscs_init->rsc_feature_attr_md.read_perm;
attr_md.write_perm = p_rscs_init->rsc_feature_attr_md.write_perm;
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 0;
memset(&attr_char_value, 0, sizeof(attr_char_value));
init_value_feature = p_rscs_init->feature;
init_value_encoded[0] = init_value_feature & 0xFF;
init_value_encoded[1] = (init_value_feature >> 8) & 0xFF;
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof (uint16_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = sizeof (uint16_t);
attr_char_value.p_value = init_value_encoded;
return sd_ble_gatts_characteristic_add(p_rscs->service_handle,
&char_md,
&attr_char_value,
&p_rscs->feature_handles);
}
uint32_t ble_rscs_init(ble_rscs_t * p_rscs, const ble_rscs_init_t * p_rscs_init)
{
if (p_rscs == NULL || p_rscs_init == NULL)
{
return NRF_ERROR_NULL;
}
uint32_t err_code;
ble_uuid_t ble_uuid;
// Initialize service structure
p_rscs->evt_handler = p_rscs_init->evt_handler;
p_rscs->conn_handle = BLE_CONN_HANDLE_INVALID;
p_rscs->feature = p_rscs_init->feature;
// Add service
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_RUNNING_SPEED_AND_CADENCE);
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
&ble_uuid,
&p_rscs->service_handle);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add measurement characteristic
err_code = rsc_measurement_char_add(p_rscs, p_rscs_init);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add feature characteristic
err_code = rsc_feature_char_add(p_rscs, p_rscs_init);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
return NRF_SUCCESS;
}
uint32_t ble_rscs_measurement_send(ble_rscs_t * p_rscs, ble_rscs_meas_t * p_measurement)
{
if (p_rscs == NULL || p_measurement == NULL)
{
return NRF_ERROR_NULL;
}
uint32_t err_code;
// Send value if connected and notifying
if (p_rscs->conn_handle != BLE_CONN_HANDLE_INVALID)
{
uint8_t encoded_rsc_meas[MAX_RSCM_LEN];
uint16_t len;
uint16_t hvx_len;
ble_gatts_hvx_params_t hvx_params;
len = rsc_measurement_encode(p_rscs, p_measurement, encoded_rsc_meas);
hvx_len = len;
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_rscs->meas_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
hvx_params.offset = 0;
hvx_params.p_len = &hvx_len;
hvx_params.p_data = encoded_rsc_meas;
err_code = sd_ble_gatts_hvx(p_rscs->conn_handle, &hvx_params);
if ((err_code == NRF_SUCCESS) && (hvx_len != len))
{
err_code = NRF_ERROR_DATA_SIZE;
}
}
else
{
err_code = NRF_ERROR_INVALID_STATE;
}
return err_code;
}

View File

@ -1,144 +0,0 @@
/* 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_rsc Running Speed and Cadence Service
* @{
* @ingroup ble_sdk_srv
* @brief Running Speed and Cadence Service module.
*
* @details This module implements the Running Speed and Cadence Service. If enabled, notification
* of the Running Speead and Candence Measurement is performed when the application
* calls ble_rscs_measurement_send().
*
* If an event handler is supplied by the application, the Running Speed and Cadence
* Service will generate Running Speed and Cadence Service events to the application.
*
* @note The application must propagate BLE stack events to the Running Speead and Candence Service
* module by calling ble_rscs_on_ble_evt() from the @ref softdevice_handler function.
*
* @note Attention!
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_RSCS_H__
#define BLE_RSCS_H__
#include <stdint.h>
#include <stdbool.h>
#include "ble.h"
#include "ble_srv_common.h"
/**@brief Running Speed and Cadence Service feature bits. */
#define BLE_RSCS_FEATURE_INSTANT_STRIDE_LEN_BIT (0x01 << 0) /**< Instantaneous Stride Length Measurement Supported bit. */
#define BLE_RSCS_FEATURE_TOTAL_DISTANCE_BIT (0x01 << 1) /**< Total Distance Measurement Supported bit. */
#define BLE_RSCS_FEATURE_WALKING_OR_RUNNING_STATUS_BIT (0x01 << 2) /**< Walking or Running Status Supported bit. */
#define BLE_RSCS_FEATURE_CALIBRATION_PROCEDURE_BIT (0x01 << 3) /**< Calibration Procedure Supported bit. */
#define BLE_RSCS_FEATURE_MULTIPLE_SENSORS_BIT (0x01 << 4) /**< Multiple Sensor Locations Supported bit. */
/**@brief Running Speed and Cadence Service event type. */
typedef enum
{
BLE_RSCS_EVT_NOTIFICATION_ENABLED, /**< Running Speed and Cadence value notification enabled event. */
BLE_RSCS_EVT_NOTIFICATION_DISABLED /**< Running Speed and Cadence value notification disabled event. */
} ble_rscs_evt_type_t;
/**@brief Running Speed and Cadence Service event. */
typedef struct
{
ble_rscs_evt_type_t evt_type; /**< Type of event. */
} ble_rscs_evt_t;
// Forward declaration of the ble_rsc types.
typedef struct ble_rscs_s ble_rscs_t;
typedef struct ble_rscs_meas_s ble_rscs_meas_t;
/**@brief Running Speed and Cadence Service event handler type. */
typedef void (*ble_rscs_evt_handler_t) (ble_rscs_t * p_rscs, ble_rscs_evt_t * p_evt);
/**@brief Running Speed and Cadence Service measurement structure. This contains a Running Speed and
* Cadence measurement. */
struct ble_rscs_meas_s
{
bool is_inst_stride_len_present; /**< True if Instantaneous Stride Length is present in the measurement. */
bool is_total_distance_present; /**< True if Total Distance is present in the measurement. */
bool is_running; /**< True if running, False if walking. */
uint16_t inst_speed; /**< Instantaneous Speed. */
uint8_t inst_cadence; /**< Instantaneous Cadence. */
uint16_t inst_stride_length; /**< Instantaneous Stride Length. */
uint32_t total_distance; /**< Total Distance. */
};
/**@brief Running Speed and Cadence Service init structure. This contains all options and data
* needed for initialization of the service. */
typedef struct
{
ble_rscs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Running Speed and Cadence Service. */
ble_srv_cccd_security_mode_t rsc_meas_attr_md; /**< Initial security level for running speed and cadence measurement attribute */
ble_srv_security_mode_t rsc_feature_attr_md; /**< Initial security level for feature attribute */
uint16_t feature; /**< Initial value for features of sensor. */
ble_rscs_meas_t initial_rcm; /**< Initial Running Speed Cadence Measurement.*/
} ble_rscs_init_t;
/**@brief Running Speed and Cadence Service structure. This contains various status information for
* the service. */
struct ble_rscs_s
{
ble_rscs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Running Speed and Cadence Service. */
uint16_t service_handle; /**< Handle of Running Speed and Cadence Service (as provided by the BLE stack). */
ble_gatts_char_handles_t meas_handles; /**< Handles related to the Running Speed and Cadence Measurement characteristic. */
ble_gatts_char_handles_t feature_handles; /**< Handles related to the Running Speed and Cadence feature characteristic. */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
uint16_t feature; /**< Bit mask of features available on sensor. */
};
/**@brief Function for initializing the Running Speed and Cadence Service.
*
* @param[out] p_rscs Running Speed and Cadence Service structure. This structure will have to
* be supplied by the application. It will be initialized by this function,
* and will later be used to identify this particular service instance.
* @param[in] p_rscs_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
*/
uint32_t ble_rscs_init(ble_rscs_t * p_rscs, const ble_rscs_init_t * p_rscs_init);
/**@brief Function for handling the Application's BLE Stack events.
*
* @details Handles all events from the BLE stack of interest to the Running Speed and Cadence
* Service.
*
* @param[in] p_rscs Running Speed and Cadence Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_rscs_on_ble_evt(ble_rscs_t * p_rscs, ble_evt_t * p_ble_evt);
/**@brief Function for sending running speed and cadence measurement if notification has been enabled.
*
* @details The application calls this function after having performed a Running Speed and Cadence
* measurement. If notification has been enabled, the measurement data is encoded and sent
* to the client.
*
* @param[in] p_rscs Running Speed and Cadence Service structure.
* @param[in] p_measurement Pointer to new running speed and cadence measurement.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
uint32_t ble_rscs_measurement_send(ble_rscs_t * p_rscs, ble_rscs_meas_t * p_measurement);
#endif // BLE_RSCS_H__
/** @} */

View File

@ -1,360 +0,0 @@
/*
* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is confidential property of Nordic Semiconductor. The use,
* copying, transfer or disclosure of such information is prohibited except by express written
* agreement with Nordic Semiconductor.
*
*/
/**@cond To Make Doxygen skip documentation generation for this file.
* @{
*/
#include "ble_rscs_c.h"
#include "ble_db_discovery.h"
#include "ble_types.h"
#include "ble_srv_common.h"
#include "ble_gattc.h"
#include "app_trace.h"
#include "sdk_common.h"
#include "nrf_log.h"
#define LOG NRF_LOG_PRINTF /**< Debug logger macro that will be used in this file to do logging of important information over UART or RTT. */
#define TX_BUFFER_MASK 0x07 /**< TX Buffer mask, must be a mask of continuous zeroes, followed by continuous 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 BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
typedef enum
{
READ_REQ, /**< Type identifying that this tx_message is a read request. */
WRITE_REQ /**< Type identifying that this tx_message is a write request. */
} tx_request_t;
/**@brief Structure for writing a message to the peer, i.e. 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 central.
*/
typedef struct
{
uint16_t conn_handle; /**< Connection handle to be used when transmitting this message. */
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 central. */
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. */
/**@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)
{
LOG("[RSCS_C]: SD Read/Write API returns Success.\r\n");
m_tx_index++;
m_tx_index &= TX_BUFFER_MASK;
}
else
{
LOG("[RSCS_C]: SD Read/Write API returns error. This message sending will be "
"attempted again..\r\n");
}
}
}
/**@brief Function for handling write response events.
*
* @param[in] p_ble_rscs_c Pointer to the Running Speed and Cadence Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_write_rsp(ble_rscs_c_t * p_ble_rscs_c, const ble_evt_t * p_ble_evt)
{
// Check if the event if on the link for this instance
if (p_ble_rscs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
{
return;
}
// Check if there is any message to be sent across to the peer and send it.
tx_buffer_process();
}
/**@brief Function for handling Handle Value Notification received from the SoftDevice.
*
* @details This function will uses the Handle Value Notification received from the SoftDevice
* and checks if it is a notification of the Running Speed and Cadence measurement from
* the peer. If it is, this function will decode the Running Speed measurement and send it
* to the application.
*
* @param[in] p_ble_rscs_c Pointer to the Running Speed and Cadence Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_hvx(ble_rscs_c_t * p_ble_rscs_c, const ble_evt_t * p_ble_evt)
{
const ble_gattc_evt_hvx_t * p_notif = &p_ble_evt->evt.gattc_evt.params.hvx;
// Check if the event if on the link for this instance
if (p_ble_rscs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
{
return;
}
// Check if this is a Running Speed and Cadence notification.
if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_rscs_c->peer_db.rsc_handle)
{
uint32_t index = 0;
ble_rscs_c_evt_t ble_rscs_c_evt;
ble_rscs_c_evt.evt_type = BLE_RSCS_C_EVT_RSC_NOTIFICATION;
ble_rscs_c_evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
//lint -save -e415 -e416 -e662 "Access of out of bounds pointer" "Creation of out of bounds pointer"
// Flags field
ble_rscs_c_evt.params.rsc.is_inst_stride_len_present = p_notif->data[index] >> BLE_RSCS_INSTANT_STRIDE_LEN_PRESENT & 0x01;
ble_rscs_c_evt.params.rsc.is_total_distance_present = p_notif->data[index] >> BLE_RSCS_TOTAL_DISTANCE_PRESENT & 0x01;
ble_rscs_c_evt.params.rsc.is_running = p_notif->data[index] >> BLE_RSCS_WALKING_OR_RUNNING_STATUS_BIT & 0x01;
index++;
// Instantaneous Speed
ble_rscs_c_evt.params.rsc.inst_speed = uint16_decode(&p_notif->data[index]);
index += sizeof(uint16_t);
// Instantaneous Cadence
ble_rscs_c_evt.params.rsc.inst_cadence = p_notif->data[index];
index++;
// Instantaneous Stride Length
if (ble_rscs_c_evt.params.rsc.is_inst_stride_len_present == true)
{
ble_rscs_c_evt.params.rsc.inst_stride_length = uint16_decode(&p_notif->data[index]);
index += sizeof(uint16_t);
}
// Total distance field
if (ble_rscs_c_evt.params.rsc.is_total_distance_present == true)
{
ble_rscs_c_evt.params.rsc.total_distance = uint32_decode(&p_notif->data[index]);
//index += sizeof(uint32_t);
}
p_ble_rscs_c->evt_handler(p_ble_rscs_c, &ble_rscs_c_evt);
//lint -restore
}
}
/**@brief Function for handling events from the database discovery module.
*
* @details This function will handle an event from the database discovery module, and determine
* if it relates to the discovery of heart rate service at the peer. If so, it will
* call the application's event handler indicating that the Running Speed and Cadence
* 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.
*
*/
void ble_rscs_on_db_disc_evt(ble_rscs_c_t * p_ble_rscs_c, const ble_db_discovery_evt_t * p_evt)
{
// Check if the Heart Rate Service was discovered.
if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_RUNNING_SPEED_AND_CADENCE &&
p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
{
ble_rscs_c_evt_t evt;
evt.conn_handle = p_evt->conn_handle;
// Find the CCCD Handle of the Running Speed and Cadence characteristic.
uint32_t i;
for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid ==
BLE_UUID_RSC_MEASUREMENT_CHAR)
{
// Found Running Speed and Cadence characteristic. Store CCCD handle and break.
evt.params.rscs_db.rsc_cccd_handle =
p_evt->params.discovered_db.charateristics[i].cccd_handle;
evt.params.rscs_db.rsc_handle =
p_evt->params.discovered_db.charateristics[i].characteristic.handle_value;
break;
}
}
LOG("[rscs_c]: Running Speed and Cadence Service discovered at peer.\r\n");
//If the instance has been assigned prior to db_discovery, assign the db_handles
if(p_ble_rscs_c->conn_handle != BLE_CONN_HANDLE_INVALID)
{
if ((p_ble_rscs_c->peer_db.rsc_cccd_handle == BLE_GATT_HANDLE_INVALID)&&
(p_ble_rscs_c->peer_db.rsc_handle == BLE_GATT_HANDLE_INVALID))
{
p_ble_rscs_c->peer_db = evt.params.rscs_db;
}
}
evt.evt_type = BLE_RSCS_C_EVT_DISCOVERY_COMPLETE;
p_ble_rscs_c->evt_handler(p_ble_rscs_c, &evt);
}
}
uint32_t ble_rscs_c_init(ble_rscs_c_t * p_ble_rscs_c, ble_rscs_c_init_t * p_ble_rscs_c_init)
{
VERIFY_PARAM_NOT_NULL(p_ble_rscs_c);
VERIFY_PARAM_NOT_NULL(p_ble_rscs_c_init);
ble_uuid_t rscs_uuid;
rscs_uuid.type = BLE_UUID_TYPE_BLE;
rscs_uuid.uuid = BLE_UUID_RUNNING_SPEED_AND_CADENCE;
p_ble_rscs_c->evt_handler = p_ble_rscs_c_init->evt_handler;
p_ble_rscs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ble_rscs_c->peer_db.rsc_cccd_handle = BLE_GATT_HANDLE_INVALID;
p_ble_rscs_c->peer_db.rsc_handle = BLE_GATT_HANDLE_INVALID;
return ble_db_discovery_evt_register(&rscs_uuid);
}
uint32_t ble_rscs_c_handles_assign(ble_rscs_c_t * p_ble_rscs_c,
uint16_t conn_handle,
ble_rscs_c_db_t * p_peer_handles)
{
VERIFY_PARAM_NOT_NULL(p_ble_rscs_c);
p_ble_rscs_c->conn_handle = conn_handle;
if (p_peer_handles != NULL)
{
p_ble_rscs_c->peer_db = *p_peer_handles;
}
return NRF_SUCCESS;
}
/**@brief Function for handling Disconnected event received from the SoftDevice.
*
* @details This function check if the disconnect event is happening on the link
* associated with the current instance of the module, if so it will set its
* conn_handle to invalid.
*
* @param[in] p_ble_rscs_c Pointer to the RSC Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_disconnected(ble_rscs_c_t * p_ble_rscs_c, const ble_evt_t * p_ble_evt)
{
if (p_ble_rscs_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
{
p_ble_rscs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ble_rscs_c->peer_db.rsc_cccd_handle = BLE_GATT_HANDLE_INVALID;
p_ble_rscs_c->peer_db.rsc_handle = BLE_GATT_HANDLE_INVALID;
}
}
void ble_rscs_c_on_ble_evt(ble_rscs_c_t * p_ble_rscs_c, const ble_evt_t * p_ble_evt)
{
if ((p_ble_rscs_c == NULL) || (p_ble_evt == NULL))
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_GATTC_EVT_HVX:
on_hvx(p_ble_rscs_c, p_ble_evt);
break;
case BLE_GATTC_EVT_WRITE_RSP:
on_write_rsp(p_ble_rscs_c, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnected(p_ble_rscs_c, p_ble_evt);
break;
default:
break;
}
}
/**@brief Function for creating a message for writing to the CCCD.
*/
static uint32_t cccd_configure(uint16_t conn_handle, uint16_t handle_cccd, bool enable)
{
LOG("[rscs_c]: Configuring CCCD. CCCD Handle = %d, Connection Handle = %d\r\n",
handle_cccd, conn_handle);
tx_message_t * p_msg;
uint16_t cccd_val = enable ? BLE_GATT_HVX_NOTIFICATION : 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 = 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_16(cccd_val);
p_msg->req.write_req.gattc_value[1] = MSB_16(cccd_val);
p_msg->conn_handle = conn_handle;
p_msg->type = WRITE_REQ;
tx_buffer_process();
return NRF_SUCCESS;
}
uint32_t ble_rscs_c_rsc_notif_enable(ble_rscs_c_t * p_ble_rscs_c)
{
VERIFY_PARAM_NOT_NULL(p_ble_rscs_c);
if (p_ble_rscs_c->conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
return cccd_configure(p_ble_rscs_c->conn_handle, p_ble_rscs_c->peer_db.rsc_cccd_handle, true);
}
/** @}
* @endcond
*/

View File

@ -1,149 +0,0 @@
#ifndef BLE_RSCS_C_H__
#define BLE_RSCS_C_H__
#include <stdint.h>
#include <stdbool.h>
#include "ble.h"
#include "ble_db_discovery.h"
/**
* @defgroup ble_sdk_srv_rscs_c Running Speed and Cadence Service Client
* @{
* @ingroup ble_sdk_srv
*
* @details This module contains the APIs and types exposed by the Running Speed and Cadence
* Service Client module. These APIs and types can be used by the application to perform
* discovery of Running Speed and Cadence Service at the peer and interact with it.
*
* @note The application must propagate BLE stack events to this module by calling
* ble_rscs_c_on_ble_evt().
*/
/**@brief Structure containing the handles related to the Running Speed and Cadence Service found on the peer. */
typedef struct
{
uint16_t rsc_cccd_handle; /**< Handle of the CCCD of the Running Speed and Cadence characteristic. */
uint16_t rsc_handle; /**< Handle of the Running Speed and Cadence characteristic as provided by the SoftDevice. */
} ble_rscs_c_db_t;
/**@brief RSCS Client event type. */
typedef enum
{
BLE_RSCS_C_EVT_DISCOVERY_COMPLETE = 1, /**< Event indicating that the Running Speed and Cadence Service has been discovered at the peer. */
BLE_RSCS_C_EVT_RSC_NOTIFICATION /**< Event indicating that a notification of the Running Speed and Cadence measurement characteristic has been received from the peer. */
} ble_rscs_c_evt_type_t;
#define BLE_RSCS_INSTANT_STRIDE_LEN_PRESENT 0x00 /**< Instantaneous Stride Length Measurement Supported bit. */
#define BLE_RSCS_TOTAL_DISTANCE_PRESENT 0x01 /**< Total Distance Measurement Supported bit. */
#define BLE_RSCS_WALKING_OR_RUNNING_STATUS_BIT 0x02 /**< Walking or Running Status Supported bit. */
/**@brief Structure containing the Running Speed and Cadence measurement received from the peer. */
typedef struct
{
bool is_inst_stride_len_present; /**< True if Instantaneous Stride Length is present in the measurement. */
bool is_total_distance_present; /**< True if Total Distance is present in the measurement. */
bool is_running; /**< True if running, False if walking. */
uint16_t inst_speed; /**< Instantaneous Speed. */
uint8_t inst_cadence; /**< Instantaneous Cadence. */
uint16_t inst_stride_length; /**< Instantaneous Stride Length. */
uint32_t total_distance; /**< Total Distance. */
} ble_rsc_t;
/**@brief Running Speed and Cadence Event structure. */
typedef struct
{
ble_rscs_c_evt_type_t evt_type; /**< Type of the event. */
uint16_t conn_handle; /**< Connection handle on which the rscs_c event occured.*/
union
{
ble_rscs_c_db_t rscs_db; /**< Running Speed and Cadence Service related handles found on the peer device. This will be filled if the evt_type is @ref BLE_RSCS_C_EVT_DISCOVERY_COMPLETE.*/
ble_rsc_t rsc; /**< Running Speed and Cadence measurement received. This will be filled if the evt_type is @ref BLE_RSCS_C_EVT_RSC_NOTIFICATION. */
} params;
} ble_rscs_c_evt_t;
// Forward declaration of the ble_rscs_c_t type.
typedef struct ble_rscs_c_s ble_rscs_c_t;
/**@brief Event handler type.
*
* @details This is the type of the event handler that should be provided by the application
* of this module in order to receive events.
*/
typedef void (* ble_rscs_c_evt_handler_t) (ble_rscs_c_t * p_ble_rscs_c, ble_rscs_c_evt_t * p_evt);
/**@brief Running Speed and Cadence client structure.
*/
struct ble_rscs_c_s
{
uint16_t conn_handle; /**< Connection handle as provided by the SoftDevice. */
ble_rscs_c_db_t peer_db; /**< Handles related to RSCS on the peer*/
ble_rscs_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the Running Speed and Cadence service. */
};
/**@brief Running Speed and Cadence client initialization structure.
*/
typedef struct
{
ble_rscs_c_evt_handler_t evt_handler; /**< Event handler to be called by the Running Speed and Cadence Client module whenever there is an event related to the Running Speed and Cadence Service. */
} ble_rscs_c_init_t;
/**@brief Function for initializing the Running Speed and Cadence Service Client module.
*
* @details This function will initialize the module and set up Database Discovery to discover
* the Running Speed and Cadence Service. After calling this function, call @ref ble_db_discovery_start
* to start discovery once a link with a peer has been established.
*
* @param[out] p_ble_rscs_c Pointer to the RSC Service client structure.
* @param[in] p_ble_rscs_c_init Pointer to the RSC Service initialization structure containing
* the initialization information.
*
* @retval NRF_SUCCESS Operation success.
* @retval NRF_ERROR_NULL A parameter is NULL.
* Otherwise, an error code returned by @ref ble_db_discovery_evt_register.
*/
uint32_t ble_rscs_c_init(ble_rscs_c_t * p_ble_rscs_c, ble_rscs_c_init_t * p_ble_rscs_c_init);
void ble_rscs_c_on_ble_evt(ble_rscs_c_t * p_ble_rscs_c, const ble_evt_t * p_ble_evt);
uint32_t ble_rscs_c_rsc_notif_enable(ble_rscs_c_t * p_ble_rscs_c);
/**@brief Function for handling events from the database discovery module.
*
* @details Call this function when getting a callback event from the DB discovery modue.
* This function will handle an event from the database discovery module, and determine
* if it relates to the discovery of Running Speed and Cadence service at the peer. If so, it will
* call the application's event handler indicating that the RSC service has been
* discovered at the peer. It also populates the event with the service related
* information before providing it to the application.
*
* @param p_ble_rscs_c Pointer to the Runnind Speed and Cadence Service client structure.
* @param[in] p_evt Pointer to the event received from the database discovery module.
*
*/
void ble_rscs_on_db_disc_evt(ble_rscs_c_t * p_ble_rscs_c, const ble_db_discovery_evt_t * p_evt);
/**@brief Function for assigning handles to a this instance of rscs_c.
*
* @details Call this function when a link has been established with a peer to
* associate this link to this instance of the module. This makes it
* possible to handle several link and associate each link to a particular
* instance of this module. The connection handle and attribute handles will be
* provided from the discovery event @ref BLE_RSCS_C_EVT_DISCOVERY_COMPLETE.
*
* @param[in] p_ble_rscs_c Pointer to the RSC client structure instance to associate.
* @param[in] conn_handle Connection handle to associated with the given RSCS Client Instance.
* @param[in] p_peer_handles Attribute handles on the RSCS server that you want this RSCS client to
* interact with.
*/
uint32_t ble_rscs_c_handles_assign(ble_rscs_c_t * p_ble_rscs_c,
uint16_t conn_handle,
ble_rscs_c_db_t * p_peer_handles);
#endif // BLE_RSCS_C_H__
/** @} */ // End tag for the file.

View File

@ -1,139 +0,0 @@
/* 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.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#include "ble_tps.h"
#include <string.h>
#include "ble_srv_common.h"
/**@brief Function for handling the Connect event.
*
* @param[in] p_tps TX Power Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_connect(ble_tps_t * p_tps, ble_evt_t * p_ble_evt)
{
p_tps->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}
void ble_tps_on_ble_evt(ble_tps_t * p_tps, ble_evt_t * p_ble_evt)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_tps, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
/**@brief Function for adding TX Power Level characteristics.
*
* @param[in] p_tps TX Power Service structure.
* @param[in] p_tps_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t tx_power_level_char_add(ble_tps_t * p_tps,
const ble_tps_init_t * p_tps_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_TX_POWER_LEVEL_CHAR);
memset(&attr_md, 0, sizeof(attr_md));
attr_md.read_perm = p_tps_init->tps_attr_md.read_perm;
attr_md.write_perm = p_tps_init->tps_attr_md.write_perm;
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 0;
memset(&attr_char_value, 0, sizeof(attr_char_value));
memset(&attr_char_value, 0, sizeof (attr_char_value));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof (int8_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = sizeof (uint8_t);
attr_char_value.p_value = (uint8_t*)&p_tps_init->initial_tx_power_level;
return sd_ble_gatts_characteristic_add(p_tps->service_handle,
&char_md,
&attr_char_value,
&p_tps->tx_power_level_handles);
}
uint32_t ble_tps_init(ble_tps_t * p_tps, const ble_tps_init_t * p_tps_init)
{
uint32_t err_code;
ble_uuid_t ble_uuid;
// Add service
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_TX_POWER_SERVICE);
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
&ble_uuid,
&p_tps->service_handle);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add TX Power Level characteristic
return tx_power_level_char_add(p_tps, p_tps_init);
}
uint32_t ble_tps_tx_power_level_set(ble_tps_t * p_tps, int8_t tx_power_level)
{
ble_gatts_value_t gatts_value;
// Initialize value struct.
memset(&gatts_value, 0, sizeof(gatts_value));
gatts_value.len = sizeof(uint8_t);
gatts_value.offset = 0;
gatts_value.p_value = (uint8_t*)&tx_power_level;
// Update database
return sd_ble_gatts_value_set(p_tps->conn_handle,
p_tps->tx_power_level_handles.value_handle,
&gatts_value);
}

View File

@ -1,86 +0,0 @@
/* 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_tps TX Power Service
* @{
* @ingroup ble_sdk_srv
* @brief TX Power Service module.
*
* @details This module implements the TX Power Service with the TX Power Level characteristic.
* During initialization it adds the TX Power Service and TX Power Level characteristic
* with the specified initial value to the BLE stack database.
*
* It provides a function for letting the application update the TX Power Level
* characteristic.
*
* @note Attention!
* To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_TPS_H__
#define BLE_TPS_H__
#include <stdint.h>
#include "ble.h"
#include "ble_srv_common.h"
/**@brief TX Power Service init structure. This contains all options and data needed for
* initialization of the service. */
typedef struct
{
int8_t initial_tx_power_level; /**< Initial value of the TX Power Level characteristic (in dBm). */
ble_srv_security_mode_t tps_attr_md; /**< Initial Security Setting for TX Power Service Characteristics. */
} ble_tps_init_t;
/**@brief TX Power Service structure. This contains various status information for the service. */
typedef struct
{
uint16_t service_handle; /**< Handle of TX Power Service (as provided by the BLE stack). */
ble_gatts_char_handles_t tx_power_level_handles; /**< Handles related to the TX Power Level characteristic. */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
} ble_tps_t;
/**@brief Function for initializing the TX Power Service.
*
* @param[out] p_hrs TX Power Service structure. This structure will have to be supplied by
* the application. It will be initialized by this function, and will later
* be used to identify this particular service instance.
* @param[in] p_tps_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
*/
uint32_t ble_tps_init(ble_tps_t * p_hrs, const ble_tps_init_t * p_tps_init);
/**@brief Function for handling the Application's BLE Stack events.
*
* @details Handles all events from the BLE stack of interest to the TX Power Service.
*
* @param[in] p_tps TX Power Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
void ble_tps_on_ble_evt(ble_tps_t * p_tps, ble_evt_t * p_ble_evt);
/**@brief Function for setting the state of the Sensor Contact Detected bit.
*
* @param[in] p_tps TX Power Service structure.
* @param[in] tx_power_level New TX Power Level (unit dBm, range -100 to 20).
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
uint32_t ble_tps_tx_power_level_set(ble_tps_t * p_tps, int8_t tx_power_level);
#endif // BLE_TPS_H__
/** @} */

View File

@ -1,58 +0,0 @@
/* Copyright (c) 2015 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_ln_common Location and Navigation common defines
* @{
* @ingroup ble_sdk_srv
* @brief Location and Navigation common defines
*
* @details This module contains define values common to LNS and LNCP
*/
#ifndef BLE_LNS_COMMON_H__
#define BLE_LNS_COMMON_H__
#define BLE_LNS_INVALID_ROUTE 0xFFFF
#define BLE_LNS_NO_FIX 0xFF
#define BLE_LNS_MAX_NUM_ROUTES 10 /**< The maximum number of routes. This affects memory usage only. */
#define BLE_LNS_MAX_ROUTE_NAME_LEN (BLE_L2CAP_MTU_DEF-5) /**< The maximum length of length of a route name. */
#define MAX_CTRL_POINT_RESP_PARAM_LEN BLE_LNS_MAX_ROUTE_NAME_LEN + 3 /**< Maximum length of a control point response. */
// Location and Navigation Service feature bits
#define BLE_LNS_FEATURE_INSTANT_SPEED_SUPPORTED (0x01 << 0) /**< Instaneous Speed Supported bit. */
#define BLE_LNS_FEATURE_TOTAL_DISTANCE_SUPPORTED (0x01 << 1) /**< Total Distance Supported bit. */
#define BLE_LNS_FEATURE_LOCATION_SUPPORTED (0x01 << 2) /**< Location Supported bit. */
#define BLE_LNS_FEATURE_ELEVATION_SUPPORTED (0x01 << 3) /**< Elevation Supported bit. */
#define BLE_LNS_FEATURE_HEADING_SUPPORTED (0x01 << 4) /**< Heading Supported bit. */
#define BLE_LNS_FEATURE_ROLLING_TIME_SUPPORTED (0x01 << 5) /**< Rolling Time Supported bit. */
#define BLE_LNS_FEATURE_UTC_TIME_SUPPORTED (0x01 << 6) /**< UTC Time Supported bit. */
#define BLE_LNS_FEATURE_REMAINING_DISTANCE_SUPPORTED (0x01 << 7) /**< Remaining Distance Supported bit. */
#define BLE_LNS_FEATURE_REMAINING_VERT_DISTANCE_SUPPORTED (0x01 << 8) /**< Remaining Vertical Distance Supported bit. */
#define BLE_LNS_FEATURE_EST_TIME_OF_ARRIVAL_SUPPORTED (0x01 << 9) /**< Estimated Time of Arrival Supported bit. */
#define BLE_LNS_FEATURE_NUM_SATS_IN_SOLUTION_SUPPORTED (0x01 << 10) /**< Number of Satellites in Solution Supported bit. */
#define BLE_LNS_FEATURE_NUM_SATS_IN_VIEW_SUPPORTED (0x01 << 11) /**< Number of Satellites in View Supported bit. */
#define BLE_LNS_FEATURE_TIME_TO_FIRST_FIX_SUPPORTED (0x01 << 12) /**< Time to First Fix Supported bit. */
#define BLE_LNS_FEATURE_EST_HORZ_POS_ERROR_SUPPORTED (0x01 << 13) /**< Estimated Horizontal Position Error Supported bit. */
#define BLE_LNS_FEATURE_EST_VERT_POS_ERROR_SUPPORTED (0x01 << 14) /**< Estimated Vertical Position Error Supported bit. */
#define BLE_LNS_FEATURE_HORZ_DILUTION_OF_PRECISION_SUPPORTED (0x01 << 15) /**< Horizontal Dilution of Precision Supported bit. */
#define BLE_LNS_FEATURE_VERT_DILUTION_OF_PRECISION_SUPPORTED (0x01 << 16) /**< Vertical Dilution of Precision Supported bit. */
#define BLE_LNS_FEATURE_LOC_AND_SPEED_CONTENT_MASKING_SUPPORTED (0x01 << 17) /**< Location and Speed Characteristic Content Masking Supported bit. */
#define BLE_LNS_FEATURE_FIX_RATE_SETTING_SUPPORTED (0x01 << 18) /**< Fix Rate Setting Supported bit. */
#define BLE_LNS_FEATURE_ELEVATION_SETTING_SUPPORTED (0x01 << 19) /**< Elevation Setting Supported bit. */
#define BLE_LNS_FEATURE_POSITION_STATUS_SUPPORTED (0x01 << 20) /**< Position Status Supported bit. */
#endif /* BLE_LNS_COMMON_H__ */
/** @} */

View File

@ -1,806 +0,0 @@
/* Copyright (c) 2015 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 "ble_ln_cp.h"
#include "ble_ln_db.h"
#include "ble_ln_common.h"
#include "sdk_common.h"
#if 0
/**
* @defgroup lncp_log Module's log macros
*
* @note LNCP_LOG will only log if DEBUG is set.
*/
#ifndef LNCP_DISABLE_LOGS
#define LNCP_LOG(format, ...) NRF_LOG_PRINTF_DEBUG("[LNCP] " format, ##__VA_ARGS__) /**< Debug logger macro */
#define LNCP_ERR(format, ...) NRF_LOG_PRINTF_ERROR("[LNCP] " format, ##__VA_ARGS__) /**< Error logger macro */
#else
#define LNCP_LOG(...)
#define LNCP_ERR(...)
#endif // LNCP_DISABLE_LOGS
#endif
#define LNCP_LOG(...)
// Feature Mask bits
#define FEATURE_MASK_INSTANTANEOUS_SPEED (0x01 << 0) /**< Instantaneous Speed mask bit. */
#define FEATURE_MASK_TOTAL_DISTANCE (0x01 << 1) /**< Total Distance mask bit. */
#define FEATURE_MASK_LOCATION (0x01 << 2) /**< Location mask bit. */
#define FEATURE_MASK_ELEVATION (0x01 << 3) /**< Elevation mask bit. */
#define FEATURE_MASK_HEADING (0x01 << 4) /**< Heading mask bit. */
#define FEATURE_MASK_ROLLING_TIME (0x01 << 5) /**< Rolling Time mask bit. */
#define FEATURE_MASK_UTC_TIME (0x01 << 6) /**< UTC Time mask bit. */
// Data Control point parameter type lengths.
#define INT8_LEN 1
#define INT16_LEN 2
#define INT24_LEN 3
#define INT32_LEN 4
#define OPCODE_LENGTH 1 /**< Length of opcode inside Location and Navigation Measurement packet. */
#define HANDLE_LENGTH 2 /**< Length of handle inside Location and Navigation Measurement packet. */
static ble_lncp_rsp_code_t notify_app(ble_lncp_t const * p_lncp, ble_lncp_evt_t const * p_evt)
{
ble_lncp_rsp_code_t rsp = LNCP_RSP_SUCCESS;
if (p_lncp->evt_handler != NULL)
{
rsp = p_lncp->evt_handler(p_lncp, p_evt);
}
return rsp;
}
static void resp_send(ble_lncp_t * p_lncp)
{
// Send indication
uint16_t hvx_len;
uint8_t hvx_data[MAX_CTRL_POINT_RESP_PARAM_LEN];
ble_gatts_hvx_params_t hvx_params;
uint32_t err_code;
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_len = 3 + p_lncp->pending_rsp.rsp_param_len;
hvx_data[0] = LNCP_OP_RESPONSE_CODE;
hvx_data[1] = p_lncp->pending_rsp.op_code;
hvx_data[2] = p_lncp->pending_rsp.rsp_code;
memcpy(&hvx_data[3], &p_lncp->pending_rsp.rsp_param[0], p_lncp->pending_rsp.rsp_param_len);
hvx_params.handle = p_lncp->ctrlpt_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_INDICATION;
hvx_params.offset = 0;
hvx_params.p_len = &hvx_len;
hvx_params.p_data = hvx_data;
err_code = sd_ble_gatts_hvx(p_lncp->conn_handle, &hvx_params);
// Error handling
if ((err_code == NRF_SUCCESS) && (hvx_len != p_lncp->pending_rsp.rsp_param_len + 3))
{
err_code = NRF_ERROR_DATA_SIZE;
}
switch (err_code)
{
case NRF_SUCCESS:
p_lncp->procedure_status = LNCP_STATE_CONFIRMATION_PENDING;
// Wait for HVC event
break;
case BLE_ERROR_NO_TX_PACKETS:
// Wait for TX_COMPLETE event to retry transmission
p_lncp->procedure_status = LNCP_STATE_INDICATION_PENDING;
break;
default:
p_lncp->procedure_status = LNCP_STATE_INDICATION_PENDING;
// error
if (p_lncp->error_handler != NULL)
{
p_lncp->error_handler(err_code);
}
break;
}
}
static void on_connect(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt)
{
memset(&p_lncp->mask, 0, sizeof(ble_lncp_mask_t));
p_lncp->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
p_lncp->procedure_status = LNCP_STATE_NO_PROC_IN_PROGRESS;
}
static void on_disconnect(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt)
{
UNUSED_PARAMETER(p_ble_evt);
p_lncp->conn_handle = BLE_CONN_HANDLE_INVALID;
p_lncp->procedure_status = LNCP_STATE_NO_PROC_IN_PROGRESS;
}
static void on_hvc_confirm(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt)
{
if (p_ble_evt->evt.gatts_evt.params.hvc.handle == p_lncp->ctrlpt_handles.value_handle)
{
if (p_lncp->procedure_status == LNCP_STATE_CONFIRMATION_PENDING)
{
p_lncp->procedure_status = LNCP_STATE_NO_PROC_IN_PROGRESS;
}
else
{
if (p_lncp->error_handler != NULL)
{
p_lncp->error_handler(NRF_ERROR_INVALID_STATE);
}
}
}
}
static void on_tx_complete(ble_lncp_t * p_lncp)
{
if (p_lncp->procedure_status == LNCP_STATE_INDICATION_PENDING)
{
resp_send(p_lncp);
}
}
/**@brief Handle write events to the control point cccd.
*
* @param[in] p_lncp Location and Navigation Service structure.
* @param[in] p_evt_write Write event received from the BLE stack.
*/
static void on_lncp_cccd_write(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
{
if (p_evt_write->len == BLE_CCCD_VALUE_LEN)
{
// CCCD written, update indications state
p_lncp->is_ctrlpt_indication_enabled = ble_srv_is_indication_enabled(p_evt_write->data);
}
}
/**@brief Handle write events to the navigation cccd.
*
* @param[in] p_lncp Location and Navigation Service structure.
* @param[in] p_evt_write Write event received from the BLE stack.
*/
static void on_nav_cccd_write(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
{
if (p_evt_write->len == BLE_CCCD_VALUE_LEN)
{
// CCCD written, update notification state
p_lncp->is_nav_notification_enabled = ble_srv_is_notification_enabled(p_evt_write->data);
}
}
/**@brief Event handler for control point write.
*
* @param[in] p_lncp Location and Navigation Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_set_cumulative_value(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
{
if ( !(p_lncp->available_features & BLE_LNS_FEATURE_TOTAL_DISTANCE_SUPPORTED) )
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
return;
}
if (p_evt_write->len != OPCODE_LENGTH + INT24_LEN)
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
return;
}
const uint32_t total_distance = uint24_decode(&p_evt_write->data[1]);
const ble_lncp_evt_t evt = {
.evt_type = LNCP_EVT_TOTAL_DISTANCE_SET,
.params.total_distance = total_distance
};
p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt);
if (p_lncp->pending_rsp.rsp_code == LNCP_RSP_SUCCESS)
{
p_lncp->total_distance = total_distance;
}
}
/**@brief Event handler for control point write.
*
* @param[in] p_lncp Location and Navigation Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_mask_loc_speed_content(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
{
if ( !(p_lncp->available_features & BLE_LNS_FEATURE_LOC_AND_SPEED_CONTENT_MASKING_SUPPORTED) )
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
return;
}
if (p_evt_write->len != OPCODE_LENGTH + INT16_LEN)
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
return;
}
uint16_t rcvd_mask = uint16_decode(&p_evt_write->data[1]);
if(rcvd_mask > 0x7F)
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
return;
}
const ble_lncp_evt_t evt = {
.evt_type = LNCP_EVT_MASK_SET,
.params.mask.flags = rcvd_mask
};
p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt);
if (p_lncp->pending_rsp.rsp_code == LNCP_RSP_SUCCESS)
{
p_lncp->mask.flags = rcvd_mask;
}
}
/**@brief Event handler for control point write.
*
* @param[in] p_lncp Location and Navigation Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_nav_control(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
{
if ( !(p_lncp->is_navigation_present) )
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
return;
}
if(p_evt_write->len != LNCP_NAV_CMD_LEN)
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
return;
}
/*lint --e{415} --e{416} -save suppress Warning 415: possible access out of bond */
const uint8_t data_buf = p_evt_write->data[1];
/*lint -restore*/
if (data_buf > LNCP_NAV_CMD_MAX)
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
return;
}
const ble_lncp_nav_cmd_t cmd = (ble_lncp_nav_cmd_t) data_buf;
if (cmd == LNCP_CMD_NAV_START || cmd == LNCP_CMD_NAV_CONTINUE || cmd == LNCP_CMD_NAV_NEAREST)
{
p_lncp->is_navigation_running = true;
}
else if (cmd == LNCP_CMD_NAV_STOP || cmd == LNCP_CMD_NAV_PAUSE)
{
p_lncp->is_navigation_running = false;
}
const ble_lncp_evt_t evt = {
.evt_type = LNCP_EVT_NAV_COMMAND,
.params.nav_cmd = cmd
};
p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt);
}
/**@brief Event handler for control point write.
*
* @param[in] p_lncp Location and Navigation Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_req_num_routes(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_SUCCESS;
if ( !(p_lncp->is_navigation_present) )
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
return;
}
if (p_evt_write->len != OPCODE_LENGTH)
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
return;
}
const uint8_t num_records = ble_ln_db_num_records_get();
p_lncp->pending_rsp.rsp_param_len = uint16_encode(num_records, &p_lncp->pending_rsp.rsp_param[0]);
}
/**@brief Event handler for control point write.
*
* @param[in] p_lncp Location and Navigation Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_req_name_of_route(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
{
uint8_t * p_name;
uint32_t err_code;
p_lncp->pending_rsp.rsp_code = LNCP_RSP_SUCCESS;
if ( !(p_lncp->is_navigation_present) )
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
return;
}
if(p_evt_write->len != OPCODE_LENGTH + INT16_LEN)
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
return;
}
/*lint --e{415} --e{416} -save suppress Warning 415: possible access out of bond */
const uint16_t route_num = uint16_decode(&p_evt_write->data[1]);
/*lint -restore*/
err_code = ble_ln_db_record_name_get(route_num, &p_name);
if (err_code != NRF_SUCCESS)
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_OPERATION_FAILED;;
return;
}
memcpy(&p_lncp->pending_rsp.rsp_param[0], p_name, BLE_LNS_MAX_ROUTE_NAME_LEN);
p_lncp->pending_rsp.rsp_param_len = BLE_LNS_MAX_ROUTE_NAME_LEN;
}
/**@brief Event handler for control point write.
*
* @param[in] p_lncp Location and Navigation Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_select_route(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
{
if ( !(p_lncp->is_navigation_present))
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
return;
}
if(p_evt_write->len != OPCODE_LENGTH + INT16_LEN)
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
return;
}
const uint16_t route_num = uint16_decode(&p_evt_write->data[1]);
const uint16_t stored_num = ble_ln_db_num_records_get();
if (route_num >= stored_num)
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
return;
}
const ble_lncp_evt_t evt = {
.evt_type = LNCP_EVT_ROUTE_SELECTED,
.params.selected_route = route_num
};
p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt);
if (p_lncp->pending_rsp.rsp_code == LNCP_RSP_SUCCESS)
{
p_lncp->selected_route = route_num;
}
}
/**@brief Event handler for control point write.
*
* @param[in] p_lncp Location and Navigation Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_set_fix_rate(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_SUCCESS;
if ( !(p_lncp->available_features & BLE_LNS_FEATURE_FIX_RATE_SETTING_SUPPORTED) )
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
return;
}
if (p_evt_write->len != OPCODE_LENGTH + INT8_LEN)
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
return;
}
/*lint --e{415} --e{416} -save suppress Warning 415: possible access out of bond */
const uint8_t fix_rate = p_evt_write->data[1];
/*lint -restore*/
const ble_lncp_evt_t evt = {
.evt_type = LNCP_EVT_FIX_RATE_SET,
.params.fix_rate = fix_rate
};
p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt);
if (p_lncp->pending_rsp.rsp_code == LNCP_RSP_SUCCESS)
{
p_lncp->fix_rate = fix_rate;
}
}
/**@brief Event handler for control point write.
*
* @param[in] p_lncp Location and Navigation Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_set_elevation(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_SUCCESS;
if ( !(p_lncp->available_features & BLE_LNS_FEATURE_ELEVATION_SETTING_SUPPORTED) )
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
return;
}
if (p_evt_write->len != OPCODE_LENGTH + INT24_LEN)
{
p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
return;
}
const uint32_t elevation = uint24_decode(&p_evt_write->data[1]);
ble_lncp_evt_t evt = {
.evt_type = LNCP_EVT_ELEVATION_SET,
.params.elevation = elevation
};
p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt);
if (p_lncp->pending_rsp.rsp_code == LNCP_RSP_SUCCESS)
{
p_lncp->elevation = elevation;
}
}
/**@brief Handle write events to the Location and Navigation Service Control Point characteristic.
*
* @param[in] p_lncp Location and Navigation Service structure.
* @param[in] p_evt_write Write event received from the BLE stack.
*/
static void on_ctrlpt_write(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
{
uint32_t err_code;
p_lncp->pending_rsp.rsp_param_len = 0;
ble_gatts_rw_authorize_reply_params_t write_authorize_reply;
memset(&write_authorize_reply, 0, sizeof(write_authorize_reply));
write_authorize_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
if (p_lncp->is_ctrlpt_indication_enabled)
{
if (p_lncp->procedure_status == LNCP_STATE_NO_PROC_IN_PROGRESS)
{
write_authorize_reply.params.write.update = 1;
write_authorize_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
// if the op code is navigation control, its cccd must be checked
if (p_evt_write->len > 0 && p_lncp->is_navigation_present)
{
if ( p_evt_write->data[0] == LNCP_OP_NAV_CONTROL
|| p_evt_write->data[0] == LNCP_OP_REQ_NAME_OF_ROUTE
|| p_evt_write->data[0] == LNCP_OP_REQ_NUM_ROUTES)
{
if (!p_lncp->is_nav_notification_enabled)
{
write_authorize_reply.params.write.gatt_status = LNCP_RSP_CCCD_CONFIG_IMPROPER;
}
}
}
}
else
{
write_authorize_reply.params.write.gatt_status = LNCP_RSP_PROC_ALR_IN_PROG;
}
}
else
{
write_authorize_reply.params.write.gatt_status = LNCP_RSP_CCCD_CONFIG_IMPROPER;
}
// reply to the write authorization
do {
err_code = sd_ble_gatts_rw_authorize_reply(p_lncp->conn_handle, &write_authorize_reply);
if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_BUSY)
{
if (p_lncp->error_handler != NULL)
{
p_lncp->error_handler(err_code);
}
}
} while (err_code == NRF_ERROR_BUSY);
if (write_authorize_reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS)
{
return;
}
// Start executing the control point write action
p_lncp->procedure_status = LNCP_STATE_INDICATION_PENDING;
if (p_evt_write->len > 0)
{
p_lncp->pending_rsp.op_code = (ble_lncp_op_code_t) p_evt_write->data[0];
switch (p_lncp->pending_rsp.op_code)
{
case LNCP_OP_SET_CUMULATIVE_VALUE:
on_set_cumulative_value(p_lncp, p_evt_write);
break;
case LNCP_OP_MASK_LOC_SPEED_CONTENT:
on_mask_loc_speed_content(p_lncp, p_evt_write);
break;
case LNCP_OP_NAV_CONTROL:
on_nav_control(p_lncp, p_evt_write);
break;
case LNCP_OP_REQ_NUM_ROUTES:
on_req_num_routes(p_lncp, p_evt_write);
break;
case LNCP_OP_REQ_NAME_OF_ROUTE:
on_req_name_of_route(p_lncp, p_evt_write);
break;
case LNCP_OP_SELECT_ROUTE:
on_select_route(p_lncp, p_evt_write);
break;
case LNCP_OP_SET_FIX_RATE:
on_set_fix_rate(p_lncp, p_evt_write);
break;
case LNCP_OP_SET_ELEVATION:
on_set_elevation(p_lncp, p_evt_write);
break;
// Unrecognized Op Code
default:
p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
break;
}
resp_send(p_lncp);
}
else
{
p_lncp->procedure_status = LNCP_STATE_NO_PROC_IN_PROGRESS;
}
}
/**@brief Write authorization request event handler.
*
* @details The write authorization request event handler is only called when writing to the control point.
*
* @param[in] p_lncp Location and Navigation Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_rw_authorize_req(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt)
{
const ble_gatts_evt_rw_authorize_request_t * p_auth_req =
&p_ble_evt->evt.gatts_evt.params.authorize_request;
if (
(p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
&&
(p_auth_req->request.write.handle == p_lncp->ctrlpt_handles.value_handle)
&&
(p_auth_req->request.write.op != BLE_GATTS_OP_PREP_WRITE_REQ)
&&
(p_auth_req->request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
&&
(p_auth_req->request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)
)
{
on_ctrlpt_write(p_lncp, &p_auth_req->request.write);
}
}
/**@brief Write event handler.
*
* @param[in] p_lncp Location and Navigation Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_write(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt)
{
const ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
if (p_evt_write->handle == p_lncp->ctrlpt_handles.cccd_handle)
{
on_lncp_cccd_write(p_lncp, p_evt_write);
}
else if (p_evt_write->handle == p_lncp->navigation_handles.cccd_handle)
{
on_nav_cccd_write(p_lncp, p_evt_write);
}
}
void ble_lncp_on_ble_evt(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt)
{
VERIFY_PARAM_NOT_NULL_VOID(p_lncp);
VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_lncp, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
if (p_ble_evt->evt.gap_evt.conn_handle == p_lncp->conn_handle)
{
on_disconnect(p_lncp, p_ble_evt);
}
break;
case BLE_GATTS_EVT_WRITE:
if (p_ble_evt->evt.gatts_evt.conn_handle == p_lncp->conn_handle)
{
on_write(p_lncp, p_ble_evt);
}
break;
case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
if (p_ble_evt->evt.gatts_evt.conn_handle == p_lncp->conn_handle)
{
on_rw_authorize_req(p_lncp, p_ble_evt);
}
break;
case BLE_GATTS_EVT_HVC:
if (p_ble_evt->evt.gatts_evt.conn_handle == p_lncp->conn_handle)
{
on_hvc_confirm(p_lncp, p_ble_evt);
}
break;
case BLE_EVT_TX_COMPLETE:
on_tx_complete(p_lncp);
break;
default:
// no implementation
break;
}
}
uint32_t ble_lncp_total_distance_get(ble_lncp_t const * p_lncp)
{
if (p_lncp == NULL)
{
return 0;
}
return p_lncp->total_distance;
}
uint32_t ble_lncp_elevation_get(ble_lncp_t const * p_lncp)
{
if (p_lncp == NULL)
{
return 0;
}
return p_lncp->elevation;
}
ble_lncp_mask_t ble_lncp_mask_get(ble_lncp_t const * p_lncp)
{
if (p_lncp == NULL)
{
const ble_lncp_mask_t empty_mask = {0};
return empty_mask;
}
return p_lncp->mask;
}
bool ble_lncp_is_navigation_running(ble_lncp_t const * p_lncp)
{
if (p_lncp == NULL)
{
return false;
}
return p_lncp->is_navigation_running;
}
ret_code_t ble_lncp_init(ble_lncp_t * p_lncp, ble_lncp_init_t const * p_lncp_init)
{
VERIFY_PARAM_NOT_NULL(p_lncp);
VERIFY_PARAM_NOT_NULL(p_lncp_init);
ble_add_char_params_t add_char_params;
memset(&add_char_params, 0, sizeof(add_char_params));
p_lncp->service_handle = p_lncp_init->service_handle;
p_lncp->evt_handler = p_lncp_init->evt_handler;
p_lncp->error_handler = p_lncp_init->error_handler;
p_lncp->available_features = p_lncp_init->available_features;
p_lncp->is_position_quality_present = p_lncp_init->is_position_quality_present;
p_lncp->is_navigation_present = p_lncp_init->is_navigation_present;
p_lncp->total_distance = p_lncp_init->total_distance;
p_lncp->elevation = p_lncp_init->elevation;
p_lncp->navigation_handles = p_lncp_init->navigation_handles;
p_lncp->fix_rate = BLE_LNS_NO_FIX;
p_lncp->selected_route = BLE_LNS_INVALID_ROUTE;
p_lncp->procedure_status = LNCP_STATE_NO_PROC_IN_PROGRESS;
p_lncp->conn_handle = BLE_CONN_HANDLE_INVALID;
p_lncp->is_navigation_running = false;
p_lncp->is_nav_notification_enabled = false;
p_lncp->is_ctrlpt_indication_enabled = false;
memset(&p_lncp->mask, 0, sizeof(ble_lncp_mask_t));
add_char_params.uuid = BLE_UUID_LN_CONTROL_POINT_CHAR;
add_char_params.max_len = 0;
add_char_params.char_props.indicate = true;
add_char_params.char_props.write = true;
add_char_params.is_defered_write = true;
add_char_params.is_var_len = true;
add_char_params.max_len = BLE_L2CAP_MTU_DEF;
add_char_params.write_access = p_lncp_init->write_perm;
add_char_params.cccd_write_access = p_lncp_init->cccd_write_perm;
LNCP_LOG("Initialized\n");
return characteristic_add(p_lncp->service_handle,
&add_char_params,
&p_lncp->ctrlpt_handles);
}

View File

@ -1,219 +0,0 @@
/* Copyright (c) 2015 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_lncp Location and Navigation Service Control Point
* @{
* @ingroup ble_sdk_srv
* @brief Location and Navigation Service Control Point module
*
* @details This module implements the Location and Navigation Service Control Point behavior.
*/
#ifndef BLE_LN_CTRLPT_H__
#define BLE_LN_CTRLPT_H__
#include "ble_srv_common.h"
#include "sdk_common.h"
#define BLE_LNS_MAX_ROUTE_NAME_LEN (BLE_L2CAP_MTU_DEF-5) /**< The maximum length of length of a route name. */
#define MAX_CTRL_POINT_RESP_PARAM_LEN BLE_LNS_MAX_ROUTE_NAME_LEN + 3 /**< Maximum length of a control point response. */
typedef struct ble_lncp_s ble_lncp_t;
/** @brief Location and Navigation event type. This list defines the possible events types from the Location and Navigation Service. */
typedef enum
{
LNCP_EVT_ELEVATION_SET, /**< Location and Navigation elevation was set. */
LNCP_EVT_FIX_RATE_SET, /**< Fix rate was set. */
LNCP_EVT_ROUTE_SELECTED, /**< A route was selected. */
LNCP_EVT_NAV_COMMAND, /**< A navigation command was issued. */
LNCP_EVT_MASK_SET, /**< Location and Speed feature mask was set. */
LNCP_EVT_TOTAL_DISTANCE_SET /**< Location and Navigation total distance was set. */
} ble_lncp_evt_type_t;
/** @brief Navigation commands. These commands can be sent to the control point and returned by an event callback. */
typedef enum
{
LNCP_CMD_NAV_STOP = 0x00, /**< When received, is_navigation_running in @ref ble_lns_s will be set to false. */
LNCP_CMD_NAV_START = 0x01, /**< When received, is_navigation_running in @ref ble_lns_s will be set to true. */
LNCP_CMD_NAV_PAUSE = 0x02, /**< When received, is_navigation_running in @ref ble_lns_s will be set to false. */
LNCP_CMD_NAV_CONTINUE = 0x03, /**< When received, is_navigation_running in @ref ble_lns_s will be set to true. */
LNCP_CMD_NAV_SKIP_WAYPOINT = 0x04, /**< When received, is_navigation_running in @ref ble_lns_s will not be affected. */
LNCP_CMD_NAV_NEAREST = 0x05, /**< When received, is_navigation_running in @ref ble_lns_s will be set to true. */
} ble_lncp_nav_cmd_t;
#define LNCP_NAV_CMD_MAX 0x05
#define LNCP_NAV_CMD_LEN (OPCODE_LENGTH + 1)
#if defined(__CC_ARM)
#pragma push
#pragma anon_unions
#elif defined(__ICCARM__)
#pragma language=extended
#elif defined(__GNUC__)
/* anonymous unions are enabled by default */
#endif
/** @brief A mask can be used to temporarily enable and disable features of the Location and Speed characteristic.*/
typedef union
{
uint8_t flags;
struct
{
uint8_t instantaneous_speed :1;
uint8_t total_distance :1;
uint8_t location :1;
uint8_t elevation :1;
uint8_t heading :1;
uint8_t rolling_time :1;
uint8_t utc_time :1;
};
} ble_lncp_mask_t;
#if defined(__CC_ARM)
#pragma pop
#elif defined(__ICCARM__)
/* leave anonymous unions enabled */
#elif defined(__GNUC__)
/* anonymous unions are enabled by default */
#endif
typedef struct
{
ble_lncp_evt_type_t evt_type;
union
{
ble_lncp_mask_t mask;
ble_lncp_nav_cmd_t nav_cmd;
uint32_t total_distance;
uint8_t fix_rate;
uint16_t selected_route;
uint32_t elevation;
} params;
} ble_lncp_evt_t;
// Location and Navigation Control Point response values
typedef enum
{
LNCP_RSP_RESERVED = 0x00, /**< Reserved for future use. */
LNCP_RSP_SUCCESS = 0x01, /**< Success. */
LNCP_RSP_OP_CODE_NOT_SUPPORTED = 0x02, /**< Op Code not supported. */
LNCP_RSP_INVALID_PARAMETER = 0x03, /**< Invalid Parameter. */
LNCP_RSP_OPERATION_FAILED = 0x04, /**< Operation Failed. */
LNCP_RSP_PROC_ALR_IN_PROG = BLE_GATT_STATUS_ATTERR_CPS_PROC_ALR_IN_PROG, /**< Control point procedure is already in progress. */
LNCP_RSP_CCCD_CONFIG_IMPROPER = BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR /**< CCCD is improperly configured. */
} ble_lncp_rsp_code_t;
typedef ble_lncp_rsp_code_t (*ble_lncp_evt_handler_t) (ble_lncp_t const * p_lncp, ble_lncp_evt_t const * p_evt);
// Location and Navigation Control Point Op Code values
typedef enum
{
LNCP_OP_RESERVED = 0x00, /**< Reserved for future use. */
LNCP_OP_SET_CUMULATIVE_VALUE = 0x01, /**< Set Cumulative Value. */
LNCP_OP_MASK_LOC_SPEED_CONTENT = 0x02, /**< Mask Location and Speed Characteristic Content. */
LNCP_OP_NAV_CONTROL = 0x03, /**< Navigation Control. */
LNCP_OP_REQ_NUM_ROUTES = 0x04, /**< Request Number of Routes. */
LNCP_OP_REQ_NAME_OF_ROUTE = 0x05, /**< Request Name of Route. */
LNCP_OP_SELECT_ROUTE = 0x06, /**< Select Route. */
LNCP_OP_SET_FIX_RATE = 0x07, /**< Set Fix Rate. */
LNCP_OP_SET_ELEVATION = 0x08, /**< Set Elevation. */
LNCP_OP_RESPONSE_CODE = 0x20 /**< Response code. */
} ble_lncp_op_code_t;
/** @brief Location and Navigation Control Point procedure status */
typedef enum
{
LNCP_STATE_NO_PROC_IN_PROGRESS, /**< No procedure in progress. */
LNCP_STATE_INDICATION_PENDING, /**< Control Point indication is pending. */
LNCP_STATE_CONFIRMATION_PENDING, /**< Waiting for the indication confirmation. */
} ble_lncp_procedure_status_t;
/** @brief Information included in a control point write response indication. */
typedef struct
{
ble_lncp_op_code_t op_code; /**< Opcode of the control point write action. */
ble_lncp_rsp_code_t rsp_code; /**< Response code of the control point write action. */
uint8_t rsp_param_len;
uint8_t rsp_param[MAX_CTRL_POINT_RESP_PARAM_LEN];
} ble_lncp_rsp_t;
typedef struct
{
uint16_t service_handle;
ble_lncp_evt_handler_t evt_handler;
ble_srv_error_handler_t error_handler;
uint32_t available_features; /**< Value of the LN feature. */
bool is_position_quality_present; /**< If set to true, the position quality characteristic will be added. Else not. */
bool is_control_point_present; /**< If set to true, the control point characteristic will be added. Else not. */
bool is_navigation_present; /**< If set to true, the navigation characteristic will be added. Else not. */
ble_gatts_char_handles_t navigation_handles;
uint32_t total_distance;
uint32_t elevation;
security_req_t write_perm;
security_req_t cccd_write_perm;
} ble_lncp_init_t;
struct ble_lncp_s
{
uint16_t conn_handle;
uint16_t service_handle;
ble_gatts_char_handles_t ctrlpt_handles;
ble_gatts_char_handles_t navigation_handles;
ble_lncp_evt_handler_t evt_handler;
ble_srv_error_handler_t error_handler;
ble_lncp_procedure_status_t procedure_status;
ble_lncp_rsp_t pending_rsp;
ble_lncp_mask_t mask;
uint32_t total_distance;
uint32_t elevation;
uint8_t fix_rate;
uint16_t selected_route;
uint32_t available_features; /**< Value of the LN feature. */
bool is_position_quality_present; /**< If set to true, the position quality characteristic will be added. Else not. */
bool is_control_point_present; /**< If set to true, the control point characteristic will be added. Else not. */
bool is_navigation_present; /**< If set to true, the navigation characteristic will be added. Else not. */
bool is_navigation_running; /**< This variable can be set using the control point. Must be true to be able to send navigation updates. */
bool is_ctrlpt_indication_enabled; /**< True if indication is enabled on the Control Point characteristic. */
bool is_nav_notification_enabled; /**< True if notification is enabled on the Navigation characteristic. */
};
void ble_lncp_on_ble_evt(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt);
uint32_t ble_lncp_total_distance_get(ble_lncp_t const * p_lncp);
uint32_t ble_lncp_elevation_get(ble_lncp_t const * p_lncp);
ble_lncp_mask_t ble_lncp_mask_get(ble_lncp_t const * p_lncp);
bool ble_lncp_is_navigation_running(ble_lncp_t const * p_lncp);
ret_code_t ble_lncp_init(ble_lncp_t * p_lncp, ble_lncp_init_t const * p_lncp_init);
#endif //BLE_LN_CTRLPT_H__
/** @} */

View File

@ -1,127 +0,0 @@
/* Copyright (c) 2015 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 "ble_ln_db.h"
#include "ble_ln_common.h"
typedef struct
{
bool in_use_flag;
ble_lns_route_t record;
} database_entry_t;
static database_entry_t m_database[BLE_LNS_MAX_NUM_ROUTES];
static uint8_t m_database_crossref[BLE_LNS_MAX_NUM_ROUTES];
static uint16_t m_num_records;
void ble_ln_db_init(void)
{
int i;
for (i = 0; i < BLE_LNS_MAX_NUM_ROUTES; i++)
{
m_database[i].in_use_flag = false;
m_database_crossref[i] = 0xFF;
}
m_num_records = 0;
}
uint16_t ble_ln_db_num_records_get(void)
{
return m_num_records;
}
ret_code_t ble_ln_db_record_get(uint8_t rec_ndx, ble_lns_route_t * p_rec)
{
if (rec_ndx >= m_num_records)
{
return NRF_ERROR_INVALID_PARAM;
}
// copy record to the specified memory
*p_rec = m_database[m_database_crossref[rec_ndx]].record;
return NRF_SUCCESS;
}
ret_code_t ble_ln_db_record_name_get(uint8_t rec_ndx, uint8_t ** p_buf)
{
if (rec_ndx >= m_num_records)
{
return NRF_ERROR_INVALID_PARAM;
}
// copy record to the specified memory
*p_buf = m_database[m_database_crossref[rec_ndx]].record.route_name;
return NRF_SUCCESS;
}
ret_code_t ble_ln_db_record_add(ble_lns_route_t * p_rec)
{
int i;
if (m_num_records == BLE_LNS_MAX_NUM_ROUTES)
{
return NRF_ERROR_NO_MEM;
}
// find next available database entry
for (i = 0; i < BLE_LNS_MAX_NUM_ROUTES; i++)
{
if (!m_database[i].in_use_flag)
{
m_database[i].in_use_flag = true;
m_database[i].record = *p_rec;
m_database[i].record.route_id = i;
m_database_crossref[m_num_records] = i;
p_rec->route_id = i;
m_num_records++;
return NRF_SUCCESS;
}
}
return NRF_ERROR_NO_MEM;
}
ret_code_t ble_ln_db_record_delete(uint8_t rec_ndx)
{
int i;
if (rec_ndx >= m_num_records)
{
return NRF_ERROR_NOT_FOUND;
}
// free entry
m_database[m_database_crossref[rec_ndx]].in_use_flag = false;
// decrease number of records
m_num_records--;
// remove cross reference index
for (i = rec_ndx; i < m_num_records; i++)
{
m_database_crossref[i] = m_database_crossref[i + 1];
}
return NRF_SUCCESS;
}

View File

@ -1,86 +0,0 @@
/* Copyright (c) 2015 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_ln_db Location and Navigation database
* @{
* @ingroup ble_sdk_srv
* @brief Location and Navigation route database
*/
#ifndef BLE_LN_DB__
#define BLE_LN_DB__
#include "ble_lns.h"
/**@brief Function for initializing the route database.
*
* @details This call initializes the database holding route records.
*
* @return NRF_SUCCESS on success.
*/
void ble_ln_db_init(void);
/**@brief Function for getting the number of records in the database.
*
* @details This call returns the number of records in the database.
*
* @return Number of records in the database.
*/
uint16_t ble_ln_db_num_records_get(void);
/**@brief Function for getting a record from the database.
*
* @details This call returns a specified record from the database.
*
* @param[in] record_num Index of the record to retrieve.
* @param[out] p_rec Pointer to record structure where retrieved record is copied to.
*
* @return NRF_SUCCESS on success.
*/
ret_code_t ble_ln_db_record_get(uint8_t record_num, ble_lns_route_t * p_rec);
/**@brief Function for getting a record name from the database.
*
* @details This call returns a specified record name from the database.
*
* @param[in] rec_ndx Index of the record to retrieve.
* @param[out] p_buf Pointer to array where retrieved record name is copied to.
*
* @return NRF_SUCCESS on success.
*/
ret_code_t ble_ln_db_record_name_get(uint8_t rec_ndx, uint8_t ** p_buf);
/**@brief Function for adding a record at the end of the database.
*
* @details This call adds a record as the last record in the database.
*
* @param[in] p_rec Pointer to record to add to database.
*
* @return NRF_SUCCESS on success.
*/
ret_code_t ble_ln_db_record_add(ble_lns_route_t * p_rec);
/**@brief Function for deleting a database entry.
*
* @details This call deletes an record from the database.
*
* @param[in] record_num Index of record to delete.
*
* @return NRF_SUCCESS on success.
*/
ret_code_t ble_ln_db_record_delete(uint8_t record_num);
#endif // BLE_LN_DB_H__
/** @} */

View File

@ -1,328 +0,0 @@
/* Copyright (c) 2015 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_lns Location and Navigation Service
* @{
* @ingroup ble_sdk_srv
* @brief Location and Navigation Service module.
*
* @details This module implements the Location and Navigation Service with the Location and Speed, Position
* Quality, Feature, Control Point, and Navigation characteristics.
*
* If an event handler is supplied by the application, the Location and Navigation Service will
* generate Location and Navigation Service events to the application.
*
* @note The application must propagate BLE stack events to the Location and Navigation Service module by calling
* @ref ble_lns_on_ble_evt() from the from the ble_stack_handler callback.
*/
#ifndef BLE_LNS_H__
#define BLE_LNS_H__
#include "ble_srv_common.h"
#include "ble_date_time.h"
#include "ble_ln_common.h"
#include "ble_ln_cp.h"
#include "sdk_common.h"
/** @brief Location and Navigation event type. This list defines the possible events types from the Location and Navigation Service. */
typedef enum {
BLE_LNS_CTRLPT_EVT_INDICATION_ENABLED, /**< Control Point value indication was enabled. */
BLE_LNS_CTRLPT_EVT_INDICATION_DISABLED, /**< Control Point value indication was disabled. */
BLE_LNS_LOC_SPEED_EVT_NOTIFICATION_ENABLED, /**< Location and Speed value notification was enabled. */
BLE_LNS_LOC_SPEED_EVT_NOTIFICATION_DISABLED, /**< Location and Speed value notification was disabled. */
BLE_LNS_NAVIGATION_EVT_NOTIFICATION_ENABLED, /**< Navigation value notification was enabled. */
BLE_LNS_NAVIGATION_EVT_NOTIFICATION_DISABLED, /**< Navigation value notification was disabled. */
} ble_lns_evt_type_t;
/** @brief Location and Navigation event structure. When an event occurs, the data structures of the module are automatically updated. */
typedef struct {
ble_lns_evt_type_t evt_type;
} ble_lns_evt_t;
// Forward declarations of the ble_lns types.
typedef struct ble_lns_init_s ble_lns_init_t;
typedef struct ble_lns_s ble_lns_t;
typedef struct ble_lns_loc_speed_s ble_lns_loc_speed_t;
typedef struct ble_lns_pos_quality_s ble_lns_pos_quality_t;
typedef struct ble_lns_navigation_s ble_lns_navigation_t;
typedef struct {
bool is_pending;
uint16_t handle;
uint16_t len;
uint8_t data[GATT_MTU_SIZE_DEFAULT];
} notification_t;
/**@brief Location and Navigation Service event handler type. */
typedef void (*ble_lns_evt_handler_t) (ble_lns_t const * p_lns, ble_lns_evt_t const * p_evt);
/**@brief Location and Navigation Service init structure. This structure contains all options and data needed to
* initialize the service. */
struct ble_lns_init_s
{
ble_lns_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Location and Navigation Service. */
ble_lncp_evt_handler_t lncp_evt_handler;
ble_srv_error_handler_t error_handler; /**< Errors will be sent back to this function. */
bool is_position_quality_present; /**< If set to true, the position quality characteristic will be added. Else not. */
bool is_control_point_present; /**< If set to true, the control point characteristic will be added. Else not. */
bool is_navigation_present; /**< If set to true, the navigation characteristic will be added. Else not. */
security_req_t loc_nav_feature_security_req_read_perm; /**< Read security level of the LN Feature characteristic. */
security_req_t loc_speed_security_req_cccd_write_perm; /**< CCCD write security level of the Write Location and Speed characteristic. */
security_req_t position_quality_security_req_read_perm; /**< Read security level of the Position Quality characteristic. */
security_req_t navigation_security_req_cccd_write_perm; /**< CCCD write security level of the Navigation characteristic. */
security_req_t ctrl_point_security_req_write_perm; /**< Read security level of the LN Control Point characteristic. */
security_req_t ctrl_point_security_req_cccd_write_perm; /**< CCCD write security level of the LN Control Point characteristic. */
uint32_t available_features; /**< Value of the LN feature. */
ble_lns_loc_speed_t * p_location_speed; /**< Initial Location and Speed. */
ble_lns_pos_quality_t * p_position_quality; /**< Initial Position Quality. */
ble_lns_navigation_t * p_navigation; /**< Initial Navigation data structure. */
};
/**@brief Definition of a navigation route.*/
typedef struct
{
uint16_t route_id;
uint8_t route_name[BLE_LNS_MAX_ROUTE_NAME_LEN];
} ble_lns_route_t;
/**@brief Location and Navigation Service structure. This structure contains various status information for the service. */
struct ble_lns_s
{
ble_lns_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Location and Navigation Service. */
ble_srv_error_handler_t error_handler; /**< Error handler. */
bool is_navigation_present; /**< If set to true, the navigation characteristic is present. Else not. */
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack; BLE_CONN_HANDLE_INVALID if not in a connection). */
uint16_t service_handle; /**< Handle of Location and Navigation Service (as provided by the BLE stack). */
ble_gatts_char_handles_t loc_speed_handles; /**< Handles related to the Location and Speed characteristic. */
ble_gatts_char_handles_t feature_handles; /**< Handles related to the Location and Navigation Feature characteristic. */
ble_gatts_char_handles_t navigation_handles; /**< Handles related to the Navigation characteristic. */
ble_gatts_char_handles_t pos_qual_handles; /**< Handles related to the Position Quality characteristic. */
ble_gatts_char_handles_t ctrlpt_handles;
uint32_t available_features; /**< Value of Location and Navigation feature. */
bool is_loc_speed_notification_enabled; /**< True if notification is enabled on the Location and Speed characteristic. */
bool is_nav_notification_enabled; /**< True if notification is enabled on the Navigation characteristic. */
notification_t pending_loc_speed_notifications[2]; /**< This buffer holds location and speed notifications. */
notification_t pending_navigation_notification; /**< This buffer holds navigation notifications. */
ble_lns_loc_speed_t * p_location_speed; /**< Location and Speed. */
ble_lns_pos_quality_t * p_position_quality; /**< Position measurement quality. */
ble_lns_navigation_t * p_navigation; /**< Navigation data structure. */
ble_lncp_t ctrl_pt;
};
/** @brief Position status. This enumeration defines how to interpret the position data. */
typedef enum
{
BLE_LNS_NO_POSITION = 0,
BLE_LNS_POSITION_OK = 1,
BLE_LNS_ESTIMATED = 2,
BLE_LNS_LAST_KNOWN_POSITION = 3
} ble_lns_pos_status_type_t;
/** @brief The format of the position and speed measurements. */
typedef enum
{
BLE_LNS_SPEED_DISTANCE_FORMAT_2D = 0,
BLE_LNS_SPEED_DISTANCE_FORMAT_3D = 1
} ble_lns_speed_distance_format_t;
/** @brief Elevation source. */
typedef enum
{
BLE_LNS_ELEV_SOURCE_POSITIONING_SYSTEM = 0,
BLE_LNS_ELEV_SOURCE_BAROMETRIC = 1,
BLE_LNS_ELEV_SOURCE_DATABASE_SERVICE = 2,
BLE_LNS_ELEV_SOURCE_OTHER = 3
} ble_lns_elevation_source_t;
/** @brief Heading source. */
typedef enum
{
BLE_LNS_HEADING_SOURCE_MOVEMENT = 0,
BLE_LNS_HEADING_SOURCE_COMPASS = 1
} ble_lns_heading_source_t;
/**@brief Location and Speed data structure. */
struct ble_lns_loc_speed_s
{
bool instant_speed_present; /**< Instantaneous Speed present (0=not present, 1=present). */
bool total_distance_present; /**< Total Distance present (0=not present, 1=present). */
bool location_present; /**< Location present (0=not present, 1=present). */
bool elevation_present; /**< Elevation present (0=not present, 1=present). */
bool heading_present; /**< Heading present (0=not present, 1=present). */
bool rolling_time_present; /**< Rolling Time present (0=not present, 1=present). */
bool utc_time_time_present; /**< UTC Time present (0=not present, 1=present). */
ble_lns_pos_status_type_t position_status; /**< Status of current position */
ble_lns_speed_distance_format_t data_format; /**< Format of data (either 2D or 3D). */
ble_lns_elevation_source_t elevation_source; /**< Source of the elevation measurement. */
ble_lns_heading_source_t heading_source; /**< Source of the heading measurement. */
uint16_t instant_speed; /**< Instantaneous Speed (1/10 meter per sec). */
uint32_t total_distance; /**< Total Distance (meters), size=24 bits. */
int32_t latitude; /**< Latitude (10e-7 degrees). */
int32_t longitude; /**< Longitude (10e-7 degrees). */
int32_t elevation; /**< Elevation (1/100 meters), size=24 bits. */
uint16_t heading; /**< Heading (1/100 degrees). */
uint8_t rolling_time; /**< Rolling Time (seconds). */
ble_date_time_t utc_time; /**< UTC Time. */
};
/** @brief Position quality structure. */
struct ble_lns_pos_quality_s
{
bool number_of_satellites_in_solution_present; /**< The number of satellites present in solution (0=not present, 1=present). */
bool number_of_satellites_in_view_present; /**< The number of satellites present in solution (0=not present, 1=present). */
bool time_to_first_fix_present; /**< Time to the first position fix present (0=not present, 1=present). */
bool ehpe_present; /**< Error in horizontal position estimate present (0=not present, 1=present). */
bool evpe_present; /**< Error in vertical position estimate present (0=not present, 1=present). */
bool hdop_present; /**< Horizontal dilution of precision present (0=not present, 1=present). */
bool vdop_present; /**< Vertical dilution of precision present (0=not present, 1=present). */
ble_lns_pos_status_type_t position_status; /**< Status of last measured position. */
uint8_t number_of_satellites_in_solution; /**< The number of satellites in solution (unitless, with a resolution of 1). */
uint8_t number_of_satellites_in_view; /**< The number of satellites in view (unitless, with a resolution of 1). */
uint16_t time_to_first_fix; /**< Time to the first position fix (seconds, with a resolution of 1/10). */
uint32_t ehpe; /**< Error in horizontal position estimate (meters, with a resolution of 1/100). */
uint32_t evpe; /**< Error in vertical position estimate (meters, with a resolution of 1/100). */
uint8_t hdop; /**< Horizontal dilution of precision (unitless, with a resolution of 2/10). */
uint8_t vdop; /**< Vertical dilution of precision (unitless, with a resolution of 2/10). */
};
/** @brief Navigation indicator type. */
typedef enum
{
BLE_LNS_NAV_TO_WAYPOINT = 0,
BLE_LNS_NAV_TO_DESTINATION = 1
} ble_lns_nav_indicator_type_t;
/**@brief Navigation data structure. */
struct ble_lns_navigation_s
{
bool remaining_dist_present; /**< Remaining Distance present (0=not present, 1=present). */
bool remaining_vert_dist_present; /**< Remaining Vertical Distance present (0=not present, 1=present). */
bool eta_present; /**< Estimated Time of Arrival present (0=not present, 1=present). */
ble_lns_pos_status_type_t position_status; /**< Status of last measured position. */
ble_lns_heading_source_t heading_source; /**< Source of the heading measurement. */
ble_lns_nav_indicator_type_t navigation_indicator_type; /**< Navigation indicator type. */
bool waypoint_reached; /**< Waypoint Reached (0=not reached, 1=reached). */
bool destination_reached; /**< Destination Reached (0=not reached, 1=reached). */
uint16_t bearing; /**< Bearing (1/100 degrees).*/
uint16_t heading; /**< Heading (1/100 degrees), size=24 bit. */
uint32_t remaining_distance; /**< Remaining Distance (1/10 meters), size=24 bit. */
int32_t remaining_vert_distance; /**< Remaining Vertical Distance (1/100 meters), size=24 bit. */
ble_date_time_t eta; /**< Estimated Time of Arrival. */
};
/**@brief Function for initializing the Location and Navigation Service.
*
* @param[out] p_lns Location and Navigation Service structure. This structure must be supplied by
* the application. It is initialized by this function, and will later
* be used to identify this particular service instance.
* @param[in] p_lns_init Information needed to initialize the service.
*
* @retval NRF_SUCCESS If the service was initialized successfully.
* @retval NRF_ERROR_NULL If a NULL parameter was provided.
* @retval NRF_INVALID_PARAMS If there is an inconsistency in the initialization structure.
* @return Otherwise, an error code from either sd_ble_gatts_service_add() or sd_ble_gatts_characteristic_add() is returned.
*/
ret_code_t ble_lns_init(ble_lns_t * p_lns, const ble_lns_init_t * p_lns_init);
/**@brief Function for handling Location and Navigation Service BLE stack events.
*
* @details This function handles all events from the BLE stack that are of interest to the Location and Navigation Service.
*
* @note The function returns when a NULL parameter is provided.
*
* @param[in] p_lns Location and Navigation Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*
*/
void ble_lns_on_ble_evt(ble_lns_t * p_lns, ble_evt_t const * p_ble_evt);
/**@brief Function for sending location and speed data if notification has been enabled.
*
* @details The application calls this function after having performed a location and speed determination.
* If notification has been enabled, the location and speed data is encoded and sent to
* the client.
*
* @param[in] p_lns Location and Navigation Service structure holding the location and speed data.
*
* @retval NRF_SUCCESS If the data was sent successfully.
* @retval NRF_ERROR_NULL If a NULL parameter was provided.
* @retval NRF_ERROR_INVALID_STATE If notification is disabled.
*/
ret_code_t ble_lns_loc_speed_send(ble_lns_t * p_lns);
/**@brief Function for sending navigation data if notification has been enabled.
*
* @details The application calls this function after having performed a navigation determination.
* If notification has been enabled, the navigation data is encoded and sent to
* the client.
*
* @param[in] p_lns Location and Navigation Service structure holding the navigation data.
*
* @retval NRF_SUCCESS If the data was sent successfully.
* @retval NRF_ERROR_NULL If a NULL parameter was provided.
* @retval NRF_ERROR_NOT_SUPPORTED If the navigation characteristic is absent.
* @retval NRF_ERROR_INVALID_STATE If navigation is not running or notification is disabled.
*/
ret_code_t ble_lns_navigation_send(ble_lns_t * p_lns);
/**@brief Function for adding a route to the Location and Navigation Service.
*
* @param[in] p_lns Location and Navigation Service structure.
* @param[in,out] p_route The new route to be added. The route ID is updated.
*
* @retval NRF_SUCCESS If the route was added successfully.
* @retval NRF_ERROR_NULL If a NULL parameter was provided.
* @retval NRF_ERROR_NOT_SUPPORTED If the navigation characteristic is absent.
* @retval NRF_ERROR_NO_MEM If there is no memory left.
* @retval NRF_ERROR_INTERNAL If there is an inconsistency in the routes table.
*/
ret_code_t ble_lns_add_route(ble_lns_t * p_lns, ble_lns_route_t * p_route);
/**@brief Function for removing a route from the Location and Navigation Service.
*
* @param[in] p_lns Location and Navigation Service structure.
* @param[in] route_id The ID of the route to be removed.
*
* @retval NRF_SUCCESS If the route was removed successfully.
* @retval NRF_ERROR_NULL If a NULL parameter was provided.
* @retval NRF_ERROR_NOT_SUPPORTED If the navigation characteristic is absent.
* @retval NRF_INVALID_PARAM If the route ID does not exist.
*/
ret_code_t ble_lns_remove_route(ble_lns_t * p_lns, uint16_t route_id);
#endif // BLE_LNS_H__
/** @} */