Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of nrf51-sdk by
app_scheduler.c
00001 /* 00002 * Copyright (c) Nordic Semiconductor ASA 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without modification, 00006 * are permitted provided that the following conditions are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright notice, this 00009 * list of conditions and the following disclaimer. 00010 * 00011 * 2. Redistributions in binary form must reproduce the above copyright notice, this 00012 * list of conditions and the following disclaimer in the documentation and/or 00013 * other materials provided with the distribution. 00014 * 00015 * 3. Neither the name of Nordic Semiconductor ASA nor the names of other 00016 * contributors to this software may be used to endorse or promote products 00017 * derived from this software without specific prior written permission. 00018 * 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00021 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00023 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 00024 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 00027 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00030 * 00031 */ 00032 00033 #include "app_scheduler.h " 00034 #include <stdlib.h> 00035 #include <stdint.h> 00036 #include <string.h> 00037 #include "nrf_soc.h" 00038 #include "nrf_assert.h" 00039 #include "app_util.h " 00040 #include "app_util_platform.h " 00041 00042 /**@brief Structure for holding a scheduled event header. */ 00043 typedef struct 00044 { 00045 app_sched_event_handler_t handler; /**< Pointer to event handler to receive the event. */ 00046 uint16_t event_data_size; /**< Size of event data. */ 00047 } event_header_t; 00048 00049 STATIC_ASSERT(sizeof(event_header_t) <= APP_SCHED_EVENT_HEADER_SIZE); 00050 00051 static event_header_t * m_queue_event_headers; /**< Array for holding the queue event headers. */ 00052 static uint8_t * m_queue_event_data; /**< Array for holding the queue event data. */ 00053 static volatile uint8_t m_queue_start_index; /**< Index of queue entry at the start of the queue. */ 00054 static volatile uint8_t m_queue_end_index; /**< Index of queue entry at the end of the queue. */ 00055 static uint16_t m_queue_event_size; /**< Maximum event size in queue. */ 00056 static uint16_t m_queue_size; /**< Number of queue entries. */ 00057 00058 /**@brief Function for incrementing a queue index, and handle wrap-around. 00059 * 00060 * @param[in] index Old index. 00061 * 00062 * @return New (incremented) index. 00063 */ 00064 static __INLINE uint8_t next_index(uint8_t index) 00065 { 00066 return (index < m_queue_size) ? (index + 1) : 0; 00067 } 00068 00069 00070 static __INLINE uint8_t app_sched_queue_full() 00071 { 00072 uint8_t tmp = m_queue_start_index; 00073 return next_index(m_queue_end_index) == tmp; 00074 } 00075 00076 /**@brief Macro for checking if a queue is full. */ 00077 #define APP_SCHED_QUEUE_FULL() app_sched_queue_full() 00078 00079 00080 static __INLINE uint8_t app_sched_queue_empty() 00081 { 00082 uint8_t tmp = m_queue_start_index; 00083 return m_queue_end_index == tmp; 00084 } 00085 00086 /**@brief Macro for checking if a queue is empty. */ 00087 #define APP_SCHED_QUEUE_EMPTY() app_sched_queue_empty() 00088 00089 00090 uint32_t app_sched_init(uint16_t event_size, uint16_t queue_size, void * p_event_buffer) 00091 { 00092 uint16_t data_start_index = (queue_size + 1) * sizeof(event_header_t); 00093 00094 // Check that buffer is correctly aligned 00095 if (!is_word_aligned(p_event_buffer)) 00096 { 00097 return NRF_ERROR_INVALID_PARAM; 00098 } 00099 00100 // Initialize event scheduler 00101 m_queue_event_headers = p_event_buffer; 00102 m_queue_event_data = &((uint8_t *)p_event_buffer)[data_start_index]; 00103 m_queue_end_index = 0; 00104 m_queue_start_index = 0; 00105 m_queue_event_size = event_size; 00106 m_queue_size = queue_size; 00107 00108 return NRF_SUCCESS; 00109 } 00110 00111 00112 uint32_t app_sched_event_put(void * p_event_data, 00113 uint16_t event_data_size, 00114 app_sched_event_handler_t handler) 00115 { 00116 uint32_t err_code; 00117 00118 if (event_data_size <= m_queue_event_size) 00119 { 00120 uint16_t event_index = 0xFFFF; 00121 00122 CRITICAL_REGION_ENTER(); 00123 00124 if (!APP_SCHED_QUEUE_FULL()) 00125 { 00126 event_index = m_queue_end_index; 00127 m_queue_end_index = next_index(m_queue_end_index); 00128 } 00129 00130 CRITICAL_REGION_EXIT(); 00131 00132 if (event_index != 0xFFFF) 00133 { 00134 // NOTE: This can be done outside the critical region since the event consumer will 00135 // always be called from the main loop, and will thus never interrupt this code. 00136 m_queue_event_headers[event_index].handler = handler; 00137 if ((p_event_data != NULL) && (event_data_size > 0)) 00138 { 00139 memcpy(&m_queue_event_data[event_index * m_queue_event_size], 00140 p_event_data, 00141 event_data_size); 00142 m_queue_event_headers[event_index].event_data_size = event_data_size; 00143 } 00144 else 00145 { 00146 m_queue_event_headers[event_index].event_data_size = 0; 00147 } 00148 00149 err_code = NRF_SUCCESS; 00150 } 00151 else 00152 { 00153 err_code = NRF_ERROR_NO_MEM; 00154 } 00155 } 00156 else 00157 { 00158 err_code = NRF_ERROR_INVALID_LENGTH; 00159 } 00160 00161 return err_code; 00162 } 00163 00164 00165 /**@brief Function for reading the next event from specified event queue. 00166 * 00167 * @param[out] pp_event_data Pointer to pointer to event data. 00168 * @param[out] p_event_data_size Pointer to size of event data. 00169 * @param[out] p_event_handler Pointer to event handler function pointer. 00170 * 00171 * @return NRF_SUCCESS if new event, NRF_ERROR_NOT_FOUND if event queue is empty. 00172 */ 00173 static uint32_t app_sched_event_get(void ** pp_event_data, 00174 uint16_t * p_event_data_size, 00175 app_sched_event_handler_t * p_event_handler) 00176 { 00177 uint32_t err_code = NRF_ERROR_NOT_FOUND; 00178 00179 if (!APP_SCHED_QUEUE_EMPTY()) 00180 { 00181 uint16_t event_index; 00182 00183 // NOTE: There is no need for a critical region here, as this function will only be called 00184 // from app_sched_execute() from inside the main loop, so it will never interrupt 00185 // app_sched_event_put(). Also, updating of (i.e. writing to) the start index will be 00186 // an atomic operation. 00187 event_index = m_queue_start_index; 00188 m_queue_start_index = next_index(m_queue_start_index); 00189 00190 *pp_event_data = &m_queue_event_data[event_index * m_queue_event_size]; 00191 *p_event_data_size = m_queue_event_headers[event_index].event_data_size; 00192 *p_event_handler = m_queue_event_headers[event_index].handler; 00193 00194 err_code = NRF_SUCCESS; 00195 } 00196 00197 return err_code; 00198 } 00199 00200 00201 void app_sched_execute(void) 00202 { 00203 void * p_event_data; 00204 uint16_t event_data_size; 00205 app_sched_event_handler_t event_handler; 00206 00207 // Get next event (if any), and execute handler 00208 while ((app_sched_event_get(&p_event_data, &event_data_size, &event_handler) == NRF_SUCCESS)) 00209 { 00210 event_handler(p_event_data, event_data_size); 00211 } 00212 }
Generated on Tue Jul 12 2022 14:11:18 by
