test

Fork of nRF51822 by Nordic Semiconductor

Committer:
rgrover1
Date:
Mon Jul 06 10:21:00 2015 +0100
Revision:
372:758e9a3a346a
Parent:
nordic-sdk/components/libraries/scheduler/app_scheduler.c@371:8f7d2137727a
Synchronized with git rev 488e2462
Author: James Crosby
restructure to yotta module, with a few tweaks to get things building

Who changed what in which revision?

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