Rob Kluin / nRF51822

Fork of nRF51822 by Nordic Semiconductor

Committer:
rgrover1
Date:
Thu Jul 02 09:08:44 2015 +0100
Revision:
362:6fa0d4d555f6
Parent:
361:d2405f5a4853
Child:
370:295f76db798e
Synchronized with git rev 2716309c
Author: Rohit Grover
Release 0.4.0
=============

This is a major release which introduces the GATT Client functionality. It
aligns with release 0.4.0 of BLE_API.

Enhancements
~~~~~~~~~~~~

* Introduce GattClient. This includes functionality for service-discovery,
connections, and attribute-reads and writes. You'll find a demo program for
LEDBlinker on the mbed.org Bluetooth team page to use the new APIs. Some of
the GATT client functionality hasn't been implemented yet, but the APIs have
been added.

* We've added an implementation for the abstract base class for
SecurityManager. All security related APIs have been moved into that.

* There has been a major cleanup of APIs under BLE. APIs have now been
categorized as belonging to Gap, GattServer, GattClient, or SecurityManager.
There are accessors to get references for Gap, GattServer, GattClient, and
SecurityManager. A former call to ble.setAddress(...) is now expected to be
achieved with ble.gap().setAddress(...).

* We've cleaned up our APIs, and this has resulted in dropping some APIs like
BLE::reset().

* We've also dropped GattServer::initializeGattDatabase(). THis was added at
some point to support controllers where a commit point was needed to
indicate when the application had finished constructing the GATT database.
This API would get called internally before Gap::startAdvertising(). We now
expect the underlying port to do the equivalent of initializeGattDatabase()
implicitly upon Gap::startAdvertising().

* We've added a version of Gap::disconnect() which takes a connection handle.
The previous API (which did not take a connection handle) has been
deprecated; it will still work for situations where there's only a single
active connection. We hold on to that API to allow existing code to migrate
to the new API.

Bugfixes
~~~~~~~~

* None.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rgrover1 362:6fa0d4d555f6 1 /*
rgrover1 362:6fa0d4d555f6 2 * Copyright (c) Nordic Semiconductor ASA
rgrover1 362:6fa0d4d555f6 3 * All rights reserved.
rgrover1 362:6fa0d4d555f6 4 *
rgrover1 362:6fa0d4d555f6 5 * Redistribution and use in source and binary forms, with or without modification,
rgrover1 362:6fa0d4d555f6 6 * are permitted provided that the following conditions are met:
rgrover1 362:6fa0d4d555f6 7 *
rgrover1 362:6fa0d4d555f6 8 * 1. Redistributions of source code must retain the above copyright notice, this
rgrover1 362:6fa0d4d555f6 9 * list of conditions and the following disclaimer.
rgrover1 362:6fa0d4d555f6 10 *
rgrover1 362:6fa0d4d555f6 11 * 2. Redistributions in binary form must reproduce the above copyright notice, this
rgrover1 362:6fa0d4d555f6 12 * list of conditions and the following disclaimer in the documentation and/or
rgrover1 362:6fa0d4d555f6 13 * other materials provided with the distribution.
rgrover1 362:6fa0d4d555f6 14 *
rgrover1 362:6fa0d4d555f6 15 * 3. Neither the name of Nordic Semiconductor ASA nor the names of other
rgrover1 362:6fa0d4d555f6 16 * contributors to this software may be used to endorse or promote products
rgrover1 362:6fa0d4d555f6 17 * derived from this software without specific prior written permission.
rgrover1 362:6fa0d4d555f6 18 *
rgrover1 362:6fa0d4d555f6 19 *
rgrover1 362:6fa0d4d555f6 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
rgrover1 362:6fa0d4d555f6 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
rgrover1 362:6fa0d4d555f6 22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
rgrover1 362:6fa0d4d555f6 23 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
rgrover1 362:6fa0d4d555f6 24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
rgrover1 362:6fa0d4d555f6 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
rgrover1 362:6fa0d4d555f6 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
rgrover1 362:6fa0d4d555f6 27 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
rgrover1 362:6fa0d4d555f6 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
rgrover1 362:6fa0d4d555f6 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
rgrover1 362:6fa0d4d555f6 30 *
rgrover1 362:6fa0d4d555f6 31 */
rgrover1 362:6fa0d4d555f6 32
rgrover1 362:6fa0d4d555f6 33 #include "app_scheduler.h"
rgrover1 362:6fa0d4d555f6 34 #include <stdlib.h>
rgrover1 362:6fa0d4d555f6 35 #include <stdint.h>
rgrover1 362:6fa0d4d555f6 36 #include <string.h>
rgrover1 362:6fa0d4d555f6 37 #include "nrf_soc.h"
rgrover1 362:6fa0d4d555f6 38 #include "nrf_assert.h"
rgrover1 362:6fa0d4d555f6 39 #include "app_util.h"
rgrover1 362:6fa0d4d555f6 40 #include "app_util_platform.h"
rgrover1 362:6fa0d4d555f6 41
rgrover1 362:6fa0d4d555f6 42 /**@brief Structure for holding a scheduled event header. */
rgrover1 362:6fa0d4d555f6 43 typedef struct
rgrover1 362:6fa0d4d555f6 44 {
rgrover1 362:6fa0d4d555f6 45 app_sched_event_handler_t handler; /**< Pointer to event handler to receive the event. */
rgrover1 362:6fa0d4d555f6 46 uint16_t event_data_size; /**< Size of event data. */
rgrover1 362:6fa0d4d555f6 47 } event_header_t;
rgrover1 362:6fa0d4d555f6 48
rgrover1 362:6fa0d4d555f6 49 STATIC_ASSERT(sizeof(event_header_t) <= APP_SCHED_EVENT_HEADER_SIZE);
rgrover1 362:6fa0d4d555f6 50
rgrover1 362:6fa0d4d555f6 51 static event_header_t * m_queue_event_headers; /**< Array for holding the queue event headers. */
rgrover1 362:6fa0d4d555f6 52 static uint8_t * m_queue_event_data; /**< Array for holding the queue event data. */
rgrover1 362:6fa0d4d555f6 53 static volatile uint8_t m_queue_start_index; /**< Index of queue entry at the start of the queue. */
rgrover1 362:6fa0d4d555f6 54 static volatile uint8_t m_queue_end_index; /**< Index of queue entry at the end of the queue. */
rgrover1 362:6fa0d4d555f6 55 static uint16_t m_queue_event_size; /**< Maximum event size in queue. */
rgrover1 362:6fa0d4d555f6 56 static uint16_t m_queue_size; /**< Number of queue entries. */
rgrover1 362:6fa0d4d555f6 57
rgrover1 362:6fa0d4d555f6 58 /**@brief Function for incrementing a queue index, and handle wrap-around.
rgrover1 362:6fa0d4d555f6 59 *
rgrover1 362:6fa0d4d555f6 60 * @param[in] index Old index.
rgrover1 362:6fa0d4d555f6 61 *
rgrover1 362:6fa0d4d555f6 62 * @return New (incremented) index.
rgrover1 362:6fa0d4d555f6 63 */
rgrover1 362:6fa0d4d555f6 64 static __INLINE uint8_t next_index(uint8_t index)
rgrover1 362:6fa0d4d555f6 65 {
rgrover1 362:6fa0d4d555f6 66 return (index < m_queue_size) ? (index + 1) : 0;
rgrover1 362:6fa0d4d555f6 67 }
rgrover1 362:6fa0d4d555f6 68
rgrover1 362:6fa0d4d555f6 69
rgrover1 362:6fa0d4d555f6 70 static __INLINE uint8_t app_sched_queue_full()
rgrover1 362:6fa0d4d555f6 71 {
rgrover1 362:6fa0d4d555f6 72 uint8_t tmp = m_queue_start_index;
rgrover1 362:6fa0d4d555f6 73 return next_index(m_queue_end_index) == tmp;
rgrover1 362:6fa0d4d555f6 74 }
rgrover1 362:6fa0d4d555f6 75
rgrover1 362:6fa0d4d555f6 76 /**@brief Macro for checking if a queue is full. */
rgrover1 362:6fa0d4d555f6 77 #define APP_SCHED_QUEUE_FULL() app_sched_queue_full()
rgrover1 362:6fa0d4d555f6 78
rgrover1 362:6fa0d4d555f6 79
rgrover1 362:6fa0d4d555f6 80 static __INLINE uint8_t app_sched_queue_empty()
rgrover1 362:6fa0d4d555f6 81 {
rgrover1 362:6fa0d4d555f6 82 uint8_t tmp = m_queue_start_index;
rgrover1 362:6fa0d4d555f6 83 return m_queue_end_index == tmp;
rgrover1 362:6fa0d4d555f6 84 }
rgrover1 362:6fa0d4d555f6 85
rgrover1 362:6fa0d4d555f6 86 /**@brief Macro for checking if a queue is empty. */
rgrover1 362:6fa0d4d555f6 87 #define APP_SCHED_QUEUE_EMPTY() app_sched_queue_empty()
rgrover1 362:6fa0d4d555f6 88
rgrover1 362:6fa0d4d555f6 89
rgrover1 362:6fa0d4d555f6 90 uint32_t app_sched_init(uint16_t event_size, uint16_t queue_size, void * p_event_buffer)
rgrover1 362:6fa0d4d555f6 91 {
rgrover1 362:6fa0d4d555f6 92 uint16_t data_start_index = (queue_size + 1) * sizeof(event_header_t);
rgrover1 362:6fa0d4d555f6 93
rgrover1 362:6fa0d4d555f6 94 // Check that buffer is correctly aligned
rgrover1 362:6fa0d4d555f6 95 if (!is_word_aligned(p_event_buffer))
rgrover1 362:6fa0d4d555f6 96 {
rgrover1 362:6fa0d4d555f6 97 return NRF_ERROR_INVALID_PARAM;
rgrover1 362:6fa0d4d555f6 98 }
rgrover1 362:6fa0d4d555f6 99
rgrover1 362:6fa0d4d555f6 100 // Initialize event scheduler
rgrover1 362:6fa0d4d555f6 101 m_queue_event_headers = p_event_buffer;
rgrover1 362:6fa0d4d555f6 102 m_queue_event_data = &((uint8_t *)p_event_buffer)[data_start_index];
rgrover1 362:6fa0d4d555f6 103 m_queue_end_index = 0;
rgrover1 362:6fa0d4d555f6 104 m_queue_start_index = 0;
rgrover1 362:6fa0d4d555f6 105 m_queue_event_size = event_size;
rgrover1 362:6fa0d4d555f6 106 m_queue_size = queue_size;
rgrover1 362:6fa0d4d555f6 107
rgrover1 362:6fa0d4d555f6 108 return NRF_SUCCESS;
rgrover1 362:6fa0d4d555f6 109 }
rgrover1 362:6fa0d4d555f6 110
rgrover1 362:6fa0d4d555f6 111
rgrover1 362:6fa0d4d555f6 112 uint32_t app_sched_event_put(void * p_event_data,
rgrover1 362:6fa0d4d555f6 113 uint16_t event_data_size,
rgrover1 362:6fa0d4d555f6 114 app_sched_event_handler_t handler)
rgrover1 362:6fa0d4d555f6 115 {
rgrover1 362:6fa0d4d555f6 116 uint32_t err_code;
rgrover1 362:6fa0d4d555f6 117
rgrover1 362:6fa0d4d555f6 118 if (event_data_size <= m_queue_event_size)
rgrover1 362:6fa0d4d555f6 119 {
rgrover1 362:6fa0d4d555f6 120 uint16_t event_index = 0xFFFF;
rgrover1 362:6fa0d4d555f6 121
rgrover1 362:6fa0d4d555f6 122 CRITICAL_REGION_ENTER();
rgrover1 362:6fa0d4d555f6 123
rgrover1 362:6fa0d4d555f6 124 if (!APP_SCHED_QUEUE_FULL())
rgrover1 362:6fa0d4d555f6 125 {
rgrover1 362:6fa0d4d555f6 126 event_index = m_queue_end_index;
rgrover1 362:6fa0d4d555f6 127 m_queue_end_index = next_index(m_queue_end_index);
rgrover1 362:6fa0d4d555f6 128 }
rgrover1 362:6fa0d4d555f6 129
rgrover1 362:6fa0d4d555f6 130 CRITICAL_REGION_EXIT();
rgrover1 362:6fa0d4d555f6 131
rgrover1 362:6fa0d4d555f6 132 if (event_index != 0xFFFF)
rgrover1 362:6fa0d4d555f6 133 {
rgrover1 362:6fa0d4d555f6 134 // NOTE: This can be done outside the critical region since the event consumer will
rgrover1 362:6fa0d4d555f6 135 // always be called from the main loop, and will thus never interrupt this code.
rgrover1 362:6fa0d4d555f6 136 m_queue_event_headers[event_index].handler = handler;
rgrover1 362:6fa0d4d555f6 137 if ((p_event_data != NULL) && (event_data_size > 0))
rgrover1 362:6fa0d4d555f6 138 {
rgrover1 362:6fa0d4d555f6 139 memcpy(&m_queue_event_data[event_index * m_queue_event_size],
rgrover1 362:6fa0d4d555f6 140 p_event_data,
rgrover1 362:6fa0d4d555f6 141 event_data_size);
rgrover1 362:6fa0d4d555f6 142 m_queue_event_headers[event_index].event_data_size = event_data_size;
rgrover1 362:6fa0d4d555f6 143 }
rgrover1 362:6fa0d4d555f6 144 else
rgrover1 362:6fa0d4d555f6 145 {
rgrover1 362:6fa0d4d555f6 146 m_queue_event_headers[event_index].event_data_size = 0;
rgrover1 362:6fa0d4d555f6 147 }
rgrover1 362:6fa0d4d555f6 148
rgrover1 362:6fa0d4d555f6 149 err_code = NRF_SUCCESS;
rgrover1 362:6fa0d4d555f6 150 }
rgrover1 362:6fa0d4d555f6 151 else
rgrover1 362:6fa0d4d555f6 152 {
rgrover1 362:6fa0d4d555f6 153 err_code = NRF_ERROR_NO_MEM;
rgrover1 362:6fa0d4d555f6 154 }
rgrover1 362:6fa0d4d555f6 155 }
rgrover1 362:6fa0d4d555f6 156 else
rgrover1 362:6fa0d4d555f6 157 {
rgrover1 362:6fa0d4d555f6 158 err_code = NRF_ERROR_INVALID_LENGTH;
rgrover1 362:6fa0d4d555f6 159 }
rgrover1 362:6fa0d4d555f6 160
rgrover1 362:6fa0d4d555f6 161 return err_code;
rgrover1 362:6fa0d4d555f6 162 }
rgrover1 362:6fa0d4d555f6 163
rgrover1 362:6fa0d4d555f6 164
rgrover1 362:6fa0d4d555f6 165 /**@brief Function for reading the next event from specified event queue.
rgrover1 362:6fa0d4d555f6 166 *
rgrover1 362:6fa0d4d555f6 167 * @param[out] pp_event_data Pointer to pointer to event data.
rgrover1 362:6fa0d4d555f6 168 * @param[out] p_event_data_size Pointer to size of event data.
rgrover1 362:6fa0d4d555f6 169 * @param[out] p_event_handler Pointer to event handler function pointer.
rgrover1 362:6fa0d4d555f6 170 *
rgrover1 362:6fa0d4d555f6 171 * @return NRF_SUCCESS if new event, NRF_ERROR_NOT_FOUND if event queue is empty.
rgrover1 362:6fa0d4d555f6 172 */
rgrover1 362:6fa0d4d555f6 173 static uint32_t app_sched_event_get(void ** pp_event_data,
rgrover1 362:6fa0d4d555f6 174 uint16_t * p_event_data_size,
rgrover1 362:6fa0d4d555f6 175 app_sched_event_handler_t * p_event_handler)
rgrover1 362:6fa0d4d555f6 176 {
rgrover1 362:6fa0d4d555f6 177 uint32_t err_code = NRF_ERROR_NOT_FOUND;
rgrover1 362:6fa0d4d555f6 178
rgrover1 362:6fa0d4d555f6 179 if (!APP_SCHED_QUEUE_EMPTY())
rgrover1 362:6fa0d4d555f6 180 {
rgrover1 362:6fa0d4d555f6 181 uint16_t event_index;
rgrover1 362:6fa0d4d555f6 182
rgrover1 362:6fa0d4d555f6 183 // NOTE: There is no need for a critical region here, as this function will only be called
rgrover1 362:6fa0d4d555f6 184 // from app_sched_execute() from inside the main loop, so it will never interrupt
rgrover1 362:6fa0d4d555f6 185 // app_sched_event_put(). Also, updating of (i.e. writing to) the start index will be
rgrover1 362:6fa0d4d555f6 186 // an atomic operation.
rgrover1 362:6fa0d4d555f6 187 event_index = m_queue_start_index;
rgrover1 362:6fa0d4d555f6 188 m_queue_start_index = next_index(m_queue_start_index);
rgrover1 362:6fa0d4d555f6 189
rgrover1 362:6fa0d4d555f6 190 *pp_event_data = &m_queue_event_data[event_index * m_queue_event_size];
rgrover1 362:6fa0d4d555f6 191 *p_event_data_size = m_queue_event_headers[event_index].event_data_size;
rgrover1 362:6fa0d4d555f6 192 *p_event_handler = m_queue_event_headers[event_index].handler;
rgrover1 362:6fa0d4d555f6 193
rgrover1 362:6fa0d4d555f6 194 err_code = NRF_SUCCESS;
rgrover1 362:6fa0d4d555f6 195 }
rgrover1 362:6fa0d4d555f6 196
rgrover1 362:6fa0d4d555f6 197 return err_code;
rgrover1 362:6fa0d4d555f6 198 }
rgrover1 362:6fa0d4d555f6 199
rgrover1 362:6fa0d4d555f6 200
rgrover1 362:6fa0d4d555f6 201 void app_sched_execute(void)
rgrover1 362:6fa0d4d555f6 202 {
rgrover1 362:6fa0d4d555f6 203 void * p_event_data;
rgrover1 362:6fa0d4d555f6 204 uint16_t event_data_size;
rgrover1 362:6fa0d4d555f6 205 app_sched_event_handler_t event_handler;
rgrover1 362:6fa0d4d555f6 206
rgrover1 362:6fa0d4d555f6 207 // Get next event (if any), and execute handler
rgrover1 362:6fa0d4d555f6 208 while ((app_sched_event_get(&p_event_data, &event_data_size, &event_handler) == NRF_SUCCESS))
rgrover1 362:6fa0d4d555f6 209 {
rgrover1 362:6fa0d4d555f6 210 event_handler(p_event_data, event_data_size);
rgrover1 362:6fa0d4d555f6 211 }
rgrover1 362:6fa0d4d555f6 212 }