Rob Kluin / nRF51822

Fork of nRF51822 by Nordic Semiconductor

Committer:
rgrover1
Date:
Fri Jun 19 15:55:35 2015 +0100
Revision:
346:14b090482fd2
Parent:
345:dfde56236c36
Child:
361:d2405f5a4853
Synchronized with git rev bb88aaad
Author: Rohit Grover
renamed BLEDevice to BLE

Who changed what in which revision?

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