konashi/SBBLEのテスト

Dependencies:   BLE_API mbed

Fork of BLE_LoopbackUART by Bluetooth Low Energy

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers app_timer.cpp Source File

app_timer.cpp

00001 /* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
00002  *
00003  * The information contained herein is property of Nordic Semiconductor ASA.
00004  * Terms and conditions of usage are described in detail in NORDIC
00005  * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
00006  *
00007  * Licensees are granted free, non-transferable use of the information. NO
00008  * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
00009  * the file.
00010  *
00011  */
00012 
00013 #include "app_timer.h "
00014 #include <stdlib.h>
00015 #include "nrf51.h"
00016 #include "nrf51_bitfields.h"
00017 #include "nrf_soc.h"
00018 #include "app_error.h "
00019 //#include "nrf_delay.h"
00020 #include "mbed.h"
00021 #include "app_util.h "
00022 #include "app_util_platform.h "
00023 
00024 
00025 #define RTC1_IRQ_PRI            APP_IRQ_PRIORITY_LOW                        /**< Priority of the RTC1 interrupt (used for checking for timeouts and executing timeout handlers). */
00026 #define SWI0_IRQ_PRI            APP_IRQ_PRIORITY_LOW                        /**< Priority of the SWI0 interrupt (used for updating the timer list). */
00027 
00028 // The current design assumes that both interrupt handlers run at the same interrupt level.
00029 // If this is to be changed, protection must be added to prevent them from interrupting each other
00030 // (e.g. by using guard/trigger flags).
00031 STATIC_ASSERT(RTC1_IRQ_PRI == SWI0_IRQ_PRI);
00032 
00033 #define MAX_RTC_COUNTER_VAL     0x00FFFFFF                                  /**< Maximum value of the RTC counter. */
00034 
00035 #define APP_HIGH_USER_ID        0                                           /**< User Id for the Application High "user". */
00036 #define APP_LOW_USER_ID         1                                           /**< User Id for the Application Low "user". */
00037 #define THREAD_MODE_USER_ID     2                                           /**< User Id for the Thread Mode "user". */
00038 
00039 #define RTC_COMPARE_OFFSET_MIN  3                                           /**< Minimum offset between the current RTC counter value and the Capture Compare register. Although the nRF51 Series User Specification recommends this value to be 2, we use 3 to be safer.*/
00040 
00041 #define MAX_RTC_TASKS_DELAY     47                                          /**< Maximum delay until an RTC task is executed. */
00042 
00043 /**@brief Timer allocation state type. */
00044 typedef enum
00045 {
00046     STATE_FREE,                                                             /**< The timer node is available. */
00047     STATE_ALLOCATED                                                         /**< The timer node has been allocated. */
00048 } timer_alloc_state_t;
00049 
00050 /**@brief Timer node type. The nodes will be used form a linked list of running timers. */
00051 typedef struct
00052 {
00053     timer_alloc_state_t         state;                                      /**< Timer allocation state. */
00054     app_timer_mode_t            mode;                                       /**< Timer mode. */
00055     uint32_t                    ticks_to_expire;                            /**< Number of ticks from previous timer interrupt to timer expiry. */
00056     uint32_t                    ticks_at_start;                             /**< Current RTC counter value when the timer was started. */
00057     uint32_t                    ticks_first_interval;                       /**< Number of ticks in the first timer interval. */
00058     uint32_t                    ticks_periodic_interval;                    /**< Timer period (for repeating timers). */
00059     bool                        is_running;                                 /**< True if timer is running, False otherwise. */
00060     app_timer_timeout_handler_t p_timeout_handler;                          /**< Pointer to function to be executed when the timer expires. */
00061     void *                      p_context;                                  /**< General purpose pointer. Will be passed to the timeout handler when the timer expires. */
00062     app_timer_id_t              next;                                       /**< Id of next timer in list of running timers. */
00063 } timer_node_t;
00064 
00065 STATIC_ASSERT(sizeof(timer_node_t) <= APP_TIMER_NODE_SIZE);
00066 STATIC_ASSERT(sizeof(timer_node_t) % 4 == 0);
00067 
00068 /**@brief Set of available timer operation types. */
00069 typedef enum
00070 {
00071     TIMER_USER_OP_TYPE_NONE,                                                /**< Invalid timer operation type. */
00072     TIMER_USER_OP_TYPE_START,                                               /**< Timer operation type Start. */
00073     TIMER_USER_OP_TYPE_STOP,                                                /**< Timer operation type Stop. */
00074     TIMER_USER_OP_TYPE_STOP_ALL                                             /**< Timer operation type Stop All. */
00075 } timer_user_op_type_t;
00076 
00077 /**@brief Structure describing a timer start operation. */
00078 typedef struct
00079 {
00080     uint32_t ticks_at_start;                                                /**< Current RTC counter value when the timer was started. */
00081     uint32_t ticks_first_interval;                                          /**< Number of ticks in the first timer interval. */
00082     uint32_t ticks_periodic_interval;                                       /**< Timer period (for repeating timers). */
00083     void *   p_context;                                                     /**< General purpose pointer. Will be passed to the timeout handler when the timer expires. */
00084 } timer_user_op_start_t;
00085 
00086 /**@brief Structure describing a timer operation. */
00087 typedef struct
00088 {
00089     timer_user_op_type_t op_type;                                           /**< Timer operation type. */
00090     app_timer_id_t       timer_id;                                          /**< Id of timer on which the operation is to be performed. */
00091     union
00092     {
00093         timer_user_op_start_t start;                                        /**< Structure describing a timer start operation. */
00094     } params;
00095 } timer_user_op_t;
00096 
00097 STATIC_ASSERT(sizeof(timer_user_op_t) <= APP_TIMER_USER_OP_SIZE);
00098 STATIC_ASSERT(sizeof(timer_user_op_t) % 4 == 0);
00099 
00100 /**@brief Structure describing a timer user.
00101  *
00102  * @details For each user of the timer module, there will be a timer operations queue. This queue
00103  *          will hold timer operations issued by this user until the timer interrupt handler
00104  *          processes these operations. For the current implementation, there will be one user for
00105  *          each interrupt level available to the application (APP_HIGH, APP_LOW and THREAD_MODE),
00106  *          but the module can easily be modified to e.g. have one queue per process when using an
00107  *          RTOS. The purpose of the queues is to be able to have a completely lockless timer
00108  *          implementation.
00109  */
00110 typedef struct
00111 {
00112     uint8_t           first;                                                    /**< Index of first entry to have been inserted in the queue (i.e. the next entry to be executed). */
00113     uint8_t           last;                                                     /**< Index of last entry to have been inserted in the queue. */
00114     uint8_t           user_op_queue_size;                                       /**< Queue size. */
00115     timer_user_op_t * p_user_op_queue;                                          /**< Queue buffer. */
00116 } timer_user_t;
00117 
00118 STATIC_ASSERT(sizeof(timer_user_t) == APP_TIMER_USER_SIZE);
00119 STATIC_ASSERT(sizeof(timer_user_t) % 4 == 0);
00120 
00121 /**@brief User id type.
00122  *
00123  * @details In the current implementation, this will automatically be generated from the current
00124  *          interrupt level.
00125  */
00126 typedef uint32_t timer_user_id_t;
00127 
00128 #define TIMER_NULL                  ((app_timer_id_t)(0 - 1))                   /**< Invalid timer id. */
00129 #define CONTEXT_QUEUE_SIZE_MAX      (2)                                         /**< Timer internal elapsed ticks queue size. */
00130 
00131 static uint8_t                       m_node_array_size;                         /**< Size of timer node array. */
00132 static timer_node_t *                mp_nodes = NULL;                           /**< Array of timer nodes. */
00133 static uint8_t                       m_user_array_size;                         /**< Size of timer user array. */
00134 static timer_user_t *                mp_users;                                  /**< Array of timer users. */
00135 static app_timer_id_t                m_timer_id_head;                           /**< First timer in list of running timers. */
00136 static uint32_t                      m_ticks_latest;                            /**< Last known RTC counter value. */
00137 static uint32_t                      m_ticks_elapsed[CONTEXT_QUEUE_SIZE_MAX];   /**< Timer internal elapsed ticks queue. */
00138 static uint8_t                       m_ticks_elapsed_q_read_ind;                /**< Timer internal elapsed ticks queue read index. */
00139 static uint8_t                       m_ticks_elapsed_q_write_ind;               /**< Timer internal elapsed ticks queue write index. */
00140 static app_timer_evt_schedule_func_t m_evt_schedule_func;                       /**< Pointer to function for propagating timeout events to the scheduler. */
00141 
00142 
00143 /**@brief Function for initializing the RTC1 counter.
00144  *
00145  * @param[in] prescaler   Value of the RTC1 PRESCALER register. Set to 0 for no prescaling.
00146  */
00147 static void rtc1_init(uint32_t prescaler)
00148 {
00149     NRF_RTC1->PRESCALER = prescaler;
00150     NVIC_SetPriority(RTC1_IRQn, RTC1_IRQ_PRI);
00151 }
00152 
00153 
00154 /**@brief Function for starting the RTC1 timer.
00155  */
00156 static void rtc1_start(void)
00157 {
00158     NRF_RTC1->EVTENSET = RTC_EVTEN_COMPARE0_Msk;
00159     NRF_RTC1->INTENSET = RTC_INTENSET_COMPARE0_Msk;
00160 
00161     NVIC_ClearPendingIRQ(RTC1_IRQn);
00162     NVIC_EnableIRQ(RTC1_IRQn);
00163 
00164     NRF_RTC1->TASKS_START = 1;
00165     wait(0.0000001 * MAX_RTC_TASKS_DELAY);
00166 }
00167 
00168 
00169 /**@brief Function for stopping the RTC1 timer.
00170  */
00171 static void rtc1_stop(void)
00172 {
00173     NVIC_DisableIRQ(RTC1_IRQn);
00174 
00175     NRF_RTC1->EVTENCLR = RTC_EVTEN_COMPARE0_Msk;
00176     NRF_RTC1->INTENCLR = RTC_INTENSET_COMPARE0_Msk;
00177 
00178     NRF_RTC1->TASKS_STOP = 1;
00179     wait(0.0000001 * MAX_RTC_TASKS_DELAY);
00180 }
00181 
00182 
00183 /**@brief Function for returning the current value of the RTC1 counter.
00184  *
00185  * @return     Current value of the RTC1 counter.
00186  */
00187 static __INLINE uint32_t rtc1_counter_get(void)
00188 {
00189     return NRF_RTC1->COUNTER;
00190 }
00191 
00192 
00193 /**@brief Function for computing the difference between two RTC1 counter values.
00194  *
00195  * @return     Number of ticks elapsed from ticks_old to ticks_now.
00196  */
00197 static __INLINE uint32_t ticks_diff_get(uint32_t ticks_now, uint32_t ticks_old)
00198 {
00199     return ((ticks_now - ticks_old) & MAX_RTC_COUNTER_VAL);
00200 }
00201 
00202 
00203 /**@brief Function for setting the RTC1 Capture Compare register 0, and enabling the corresponding
00204  *        event.
00205  *
00206  * @param[in] value   New value of Capture Compare register 0.
00207  */
00208 static __INLINE void rtc1_compare0_set(uint32_t value)
00209 {
00210     NRF_RTC1->CC[0] = value;
00211 }
00212 
00213 
00214 /**@brief Function for inserting a timer in the timer list.
00215  *
00216  * @param[in]  timer_id   Id of timer to insert.
00217  */
00218 static void timer_list_insert(app_timer_id_t timer_id)
00219 {
00220     timer_node_t * p_timer = &mp_nodes[timer_id];
00221 
00222     if (m_timer_id_head == TIMER_NULL)
00223     {
00224         m_timer_id_head = timer_id;
00225     }
00226     else
00227     {
00228         if (p_timer->ticks_to_expire <= mp_nodes[m_timer_id_head].ticks_to_expire)
00229         {
00230             mp_nodes[m_timer_id_head].ticks_to_expire -= p_timer->ticks_to_expire;
00231 
00232             p_timer->next   = m_timer_id_head;
00233             m_timer_id_head = timer_id;
00234         }
00235         else
00236         {
00237             app_timer_id_t previous;
00238             app_timer_id_t current;
00239             uint32_t       ticks_to_expire;
00240 
00241             ticks_to_expire = p_timer->ticks_to_expire;
00242             previous        = m_timer_id_head;
00243             current         = m_timer_id_head;
00244 
00245             while ((current != TIMER_NULL) && (ticks_to_expire > mp_nodes[current].ticks_to_expire))
00246             {
00247                 ticks_to_expire -= mp_nodes[current].ticks_to_expire;
00248                 previous         = current;
00249                 current          = mp_nodes[current].next;
00250             }
00251 
00252             if (current != TIMER_NULL)
00253             {
00254                 mp_nodes[current].ticks_to_expire -= ticks_to_expire;
00255             }
00256 
00257             p_timer->ticks_to_expire = ticks_to_expire;
00258             p_timer->next            = current;
00259             mp_nodes[previous].next  = timer_id;
00260         }
00261     }
00262 }
00263 
00264 
00265 /**@brief Function for removing a timer from the timer queue.
00266  *
00267  * @param[in]  timer_id   Id of timer to remove.
00268  */
00269 static void timer_list_remove(app_timer_id_t timer_id)
00270 {
00271     app_timer_id_t previous;
00272     app_timer_id_t current;
00273     uint32_t       timeout;
00274 
00275     // Find the timer's position in timer list
00276     previous = m_timer_id_head;
00277     current  = previous;
00278 
00279     while (current != TIMER_NULL)
00280     {
00281         if (current == timer_id)
00282         {
00283             break;
00284         }
00285         previous = current;
00286         current  = mp_nodes[current].next;
00287     }
00288 
00289     // Timer not in active list
00290     if (current == TIMER_NULL)
00291     {
00292         return;
00293     }
00294 
00295     // Timer is the first in the list
00296     if (previous == current)
00297     {
00298         m_timer_id_head = mp_nodes[m_timer_id_head].next;
00299     }
00300 
00301     // Remaining timeout between next timeout
00302     timeout = mp_nodes[current].ticks_to_expire;
00303 
00304     // Link previous timer with next of this timer, i.e. removing the timer from list
00305     mp_nodes[previous].next = mp_nodes[current].next;
00306 
00307     // If this is not the last timer, increment the next timer by this timer timeout
00308     current = mp_nodes[previous].next;
00309     if (current != TIMER_NULL)
00310     {
00311         mp_nodes[current].ticks_to_expire += timeout;
00312     }
00313 }
00314 
00315 
00316 /**@brief Function for scheduling a check for timeouts by generating a RTC1 interrupt.
00317  */
00318 static void timer_timeouts_check_sched(void)
00319 {
00320     NVIC_SetPendingIRQ(RTC1_IRQn);
00321 }
00322 
00323 
00324 /**@brief Function for scheduling a timer list update by generating a SWI0 interrupt.
00325  */
00326 static void timer_list_handler_sched(void)
00327 {
00328     NVIC_SetPendingIRQ(SWI0_IRQn);
00329 }
00330 
00331 
00332 /**@brief Function for executing an application timeout handler, either by calling it directly, or
00333  *        by passing an event to the @ref app_scheduler.
00334  *
00335  * @param[in]  p_timer   Pointer to expired timer.
00336  */
00337 static void timeout_handler_exec(timer_node_t * p_timer)
00338 {
00339     if (m_evt_schedule_func != NULL)
00340     {
00341         uint32_t err_code = m_evt_schedule_func(p_timer->p_timeout_handler, p_timer->p_context);
00342         APP_ERROR_CHECK(err_code);
00343     }
00344     else
00345     {
00346         p_timer->p_timeout_handler(p_timer->p_context);
00347     }
00348 }
00349 
00350 
00351 /**@brief Function for checking for expired timers.
00352  */
00353 static void timer_timeouts_check(void)
00354 {
00355     // Handle expired of timer
00356     if (m_timer_id_head != TIMER_NULL)
00357     {
00358         app_timer_id_t  timer_id;
00359         uint32_t        ticks_elapsed;
00360         uint32_t        ticks_expired;
00361 
00362         // Initialize actual elapsed ticks being consumed to 0
00363         ticks_expired = 0;
00364 
00365         // ticks_elapsed is collected here, job will use it
00366         ticks_elapsed = ticks_diff_get(rtc1_counter_get(), m_ticks_latest);
00367 
00368         // Auto variable containing the head of timers expiring
00369         timer_id = m_timer_id_head;
00370 
00371         // Expire all timers within ticks_elapsed and collect ticks_expired
00372         while (timer_id != TIMER_NULL)
00373         {
00374             timer_node_t * p_timer;
00375 
00376             // Auto variable for current timer node
00377             p_timer = &mp_nodes[timer_id];
00378 
00379             // Do nothing if timer did not expire
00380             if (ticks_elapsed < p_timer->ticks_to_expire)
00381             {
00382                 break;
00383             }
00384 
00385             // Decrement ticks_elapsed and collect expired ticks
00386             ticks_elapsed -= p_timer->ticks_to_expire;
00387             ticks_expired += p_timer->ticks_to_expire;
00388 
00389             // Move to next timer
00390             timer_id = p_timer->next;
00391 
00392             // Execute Task
00393             timeout_handler_exec(p_timer);
00394         }
00395 
00396         // Prepare to queue the ticks expired in the m_ticks_elapsed queue.
00397         if (m_ticks_elapsed_q_read_ind == m_ticks_elapsed_q_write_ind)
00398         {
00399             // The read index of the queue is equal to the write index. This means the new
00400             // value of ticks_expired should be stored at a new location in the m_ticks_elapsed
00401             // queue (which is implemented as a double buffer).
00402 
00403             // Check if there will be a queue overflow.
00404             if (++m_ticks_elapsed_q_write_ind == CONTEXT_QUEUE_SIZE_MAX)
00405             {
00406                 // There will be a queue overflow. Hence the write index should point to the start
00407                 // of the queue.
00408                 m_ticks_elapsed_q_write_ind = 0;
00409             }
00410         }
00411 
00412         // Queue the ticks expired.
00413         m_ticks_elapsed[m_ticks_elapsed_q_write_ind] = ticks_expired;
00414 
00415         timer_list_handler_sched();
00416     }
00417 }
00418 
00419 
00420 /**@brief Function for acquiring the number of ticks elapsed.
00421  *
00422  * @param[out] p_ticks_elapsed   Number of ticks elapsed.
00423  *
00424  * @return     TRUE if elapsed ticks was read from queue, FALSE otherwise.
00425  */
00426 static bool elapsed_ticks_acquire(uint32_t * p_ticks_elapsed)
00427 {
00428     // Pick the elapsed value from queue
00429     if (m_ticks_elapsed_q_read_ind != m_ticks_elapsed_q_write_ind)
00430     {
00431         // Dequeue elapsed value
00432         m_ticks_elapsed_q_read_ind++;
00433         if (m_ticks_elapsed_q_read_ind == CONTEXT_QUEUE_SIZE_MAX)
00434         {
00435             m_ticks_elapsed_q_read_ind = 0;
00436         }
00437 
00438         *p_ticks_elapsed = m_ticks_elapsed[m_ticks_elapsed_q_read_ind];
00439 
00440         m_ticks_latest += *p_ticks_elapsed;
00441         m_ticks_latest &= MAX_RTC_COUNTER_VAL;
00442 
00443         return true;
00444     }
00445     else
00446     {
00447         // No elapsed value in queue
00448         *p_ticks_elapsed = 0;
00449         return false;
00450     }
00451 }
00452 
00453 
00454 /**@brief Function for handling the timer list deletions.
00455  *
00456  * @return     TRUE if Capture Compare register must be updated, FALSE otherwise.
00457  */
00458 static bool list_deletions_handler(void)
00459 {
00460     app_timer_id_t timer_id_old_head;
00461     uint8_t        user_id;
00462 
00463     // Remember the old head, so as to decide if new compare needs to be set
00464     timer_id_old_head = m_timer_id_head;
00465 
00466     user_id = m_user_array_size;
00467     while (user_id--)
00468     {
00469         timer_user_t * p_user         = &mp_users[user_id];
00470         uint8_t        user_ops_first = p_user->first;
00471 
00472         while (user_ops_first != p_user->last)
00473         {
00474             timer_node_t *    p_timer;
00475             timer_user_op_t * p_user_op = &p_user->p_user_op_queue[user_ops_first];
00476 
00477             // Traverse to next operation in queue
00478             user_ops_first++;
00479             if (user_ops_first == p_user->user_op_queue_size)
00480             {
00481                 user_ops_first = 0;
00482             }
00483 
00484             switch (p_user_op->op_type)
00485             {
00486                 case TIMER_USER_OP_TYPE_STOP:
00487                     // Delete node if timer is running
00488                     p_timer = &mp_nodes[p_user_op->timer_id];
00489                     if (p_timer->is_running)
00490                     {
00491                         timer_list_remove(p_user_op->timer_id);
00492                         p_timer->is_running = false;
00493                     }
00494                     break;
00495 
00496                 case TIMER_USER_OP_TYPE_STOP_ALL:
00497                     // Delete list of running timers, and mark all timers as not running
00498                     while (m_timer_id_head != TIMER_NULL)
00499                     {
00500                         timer_node_t * p_head = &mp_nodes[m_timer_id_head];
00501 
00502                         p_head->is_running = false;
00503                         m_timer_id_head    = p_head->next;
00504                     }
00505                     break;
00506 
00507                 default:
00508                     // No implementation needed.
00509                     break;
00510             }
00511         }
00512     }
00513 
00514     // Detect change in head of the list
00515     return (m_timer_id_head != timer_id_old_head);
00516 }
00517 
00518 
00519 /**@brief Function for updating the timer list for expired timers.
00520  *
00521  * @param[in]  ticks_elapsed         Number of elapsed ticks.
00522  * @param[in]  ticks_previous        Previous known value of the RTC counter.
00523  * @param[out] p_restart_list_head   List of repeating timers to be restarted.
00524  */
00525 static void expired_timers_handler(uint32_t         ticks_elapsed,
00526                                    uint32_t         ticks_previous,
00527                                    app_timer_id_t * p_restart_list_head)
00528 {
00529     uint32_t ticks_expired = 0;
00530 
00531     while (m_timer_id_head != TIMER_NULL)
00532     {
00533         timer_node_t * p_timer;
00534         app_timer_id_t id_expired;
00535 
00536         // Auto variable for current timer node
00537         p_timer = &mp_nodes[m_timer_id_head];
00538 
00539         // Do nothing if timer did not expire
00540         if (ticks_elapsed < p_timer->ticks_to_expire)
00541         {
00542             p_timer->ticks_to_expire -= ticks_elapsed;
00543             break;
00544         }
00545 
00546         // Decrement ticks_elapsed and collect expired ticks
00547         ticks_elapsed -= p_timer->ticks_to_expire;
00548         ticks_expired += p_timer->ticks_to_expire;
00549 
00550         // Timer expired, set ticks_to_expire zero
00551         p_timer->ticks_to_expire = 0;
00552         p_timer->is_running      = false;
00553 
00554         // Remove the expired timer from head
00555         id_expired      = m_timer_id_head;
00556         m_timer_id_head = p_timer->next;
00557 
00558         // Timer will be restarted if periodic
00559         if (p_timer->ticks_periodic_interval != 0)
00560         {
00561             p_timer->ticks_at_start       = (ticks_previous + ticks_expired) & MAX_RTC_COUNTER_VAL;
00562             p_timer->ticks_first_interval = p_timer->ticks_periodic_interval;
00563             p_timer->next                 = *p_restart_list_head;
00564             *p_restart_list_head          = id_expired;
00565         }
00566     }
00567 }
00568 
00569 
00570 /**@brief Function for handling timer list insertions.
00571  *
00572  * @param[in]  p_restart_list_head   List of repeating timers to be restarted.
00573  *
00574  * @return     TRUE if Capture Compare register must be updated, FALSE otherwise.
00575  */
00576 static bool list_insertions_handler(app_timer_id_t restart_list_head)
00577 {
00578     app_timer_id_t timer_id_old_head;
00579     uint8_t        user_id;
00580 
00581     // Remember the old head, so as to decide if new compare needs to be set
00582     timer_id_old_head = m_timer_id_head;
00583 
00584     user_id = m_user_array_size;
00585     while (user_id--)
00586     {
00587         timer_user_t * p_user = &mp_users[user_id];
00588 
00589         // Handle insertions of timers
00590         while ((restart_list_head != TIMER_NULL) || (p_user->first != p_user->last))
00591         {
00592             app_timer_id_t id_start;
00593             timer_node_t * p_timer;
00594 
00595             if (restart_list_head != TIMER_NULL)
00596             {
00597                 id_start          = restart_list_head;
00598                 p_timer           = &mp_nodes[id_start];
00599                 restart_list_head = p_timer->next;
00600             }
00601             else
00602             {
00603                 timer_user_op_t * p_user_op = &p_user->p_user_op_queue[p_user->first];
00604 
00605                 p_user->first++;
00606                 if (p_user->first == p_user->user_op_queue_size)
00607                 {
00608                     p_user->first = 0;
00609                 }
00610 
00611                 id_start = p_user_op->timer_id;
00612                 p_timer  = &mp_nodes[id_start];
00613 
00614                 if ((p_user_op->op_type != TIMER_USER_OP_TYPE_START) || p_timer->is_running)
00615                 {
00616                     continue;
00617                 }
00618 
00619                 p_timer->ticks_at_start          = p_user_op->params.start.ticks_at_start;
00620                 p_timer->ticks_first_interval    = p_user_op->params.start.ticks_first_interval;
00621                 p_timer->ticks_periodic_interval = p_user_op->params.start.ticks_periodic_interval;
00622                 p_timer->p_context               = p_user_op->params.start.p_context;
00623             }
00624 
00625             // Prepare the node to be inserted
00626             if (
00627                  ((p_timer->ticks_at_start - m_ticks_latest) & MAX_RTC_COUNTER_VAL)
00628                  <
00629                  (MAX_RTC_COUNTER_VAL / 2)
00630                 )
00631             {
00632                 p_timer->ticks_to_expire = ticks_diff_get(p_timer->ticks_at_start, m_ticks_latest) +
00633                                            p_timer->ticks_first_interval;
00634             }
00635             else
00636             {
00637                 uint32_t delta_current_start;
00638 
00639                 delta_current_start = ticks_diff_get(m_ticks_latest, p_timer->ticks_at_start);
00640                 if (p_timer->ticks_first_interval > delta_current_start)
00641                 {
00642                     p_timer->ticks_to_expire = p_timer->ticks_first_interval - delta_current_start;
00643                 }
00644                 else
00645                 {
00646                     p_timer->ticks_to_expire = 0;
00647                 }
00648             }
00649 
00650             p_timer->ticks_at_start       = 0;
00651             p_timer->ticks_first_interval = 0;
00652             p_timer->is_running           = true;
00653             p_timer->next                 = TIMER_NULL;
00654 
00655             // Insert into list
00656             timer_list_insert(id_start);
00657         }
00658     }
00659 
00660     return (m_timer_id_head != timer_id_old_head);
00661 }
00662 
00663 
00664 /**@brief Function for updating the Capture Compare register.
00665  */
00666 static void compare_reg_update(app_timer_id_t timer_id_head_old)
00667 {
00668     // Setup the timeout for timers on the head of the list
00669     if (m_timer_id_head != TIMER_NULL)
00670     {
00671         uint32_t ticks_to_expire = mp_nodes[m_timer_id_head].ticks_to_expire;
00672         uint32_t pre_counter_val = rtc1_counter_get();
00673         uint32_t cc              = m_ticks_latest;
00674         uint32_t ticks_elapsed   = ticks_diff_get(pre_counter_val, cc) + RTC_COMPARE_OFFSET_MIN;
00675 
00676         if (timer_id_head_old == TIMER_NULL)
00677         {
00678             // No timers were already running, start RTC
00679             rtc1_start();
00680         }
00681 
00682         cc += (ticks_elapsed < ticks_to_expire) ? ticks_to_expire : ticks_elapsed;
00683         cc &= MAX_RTC_COUNTER_VAL;
00684 
00685         rtc1_compare0_set(cc);
00686 
00687         uint32_t post_counter_val = rtc1_counter_get();
00688 
00689         if (
00690             (ticks_diff_get(post_counter_val, pre_counter_val) + RTC_COMPARE_OFFSET_MIN)
00691             >
00692             ticks_diff_get(cc, pre_counter_val)
00693            )
00694         {
00695             // When this happens the COMPARE event may not be triggered by the RTC.
00696             // The nRF51 Series User Specification states that if the COUNTER value is N
00697             // (i.e post_counter_val = N), writing N or N+1 to a CC register may not trigger a
00698             // COMPARE event. Hence the RTC interrupt is forcefully pended by calling the following
00699             // function.
00700             timer_timeouts_check_sched();
00701         }
00702     }
00703     else
00704     {
00705         // No timers are running, stop RTC
00706         rtc1_stop();
00707     }
00708 }
00709 
00710 
00711 /**@brief Function for handling changes to the timer list.
00712  */
00713 static void timer_list_handler(void)
00714 {
00715     app_timer_id_t restart_list_head = TIMER_NULL;
00716     uint32_t       ticks_elapsed;
00717     uint32_t       ticks_previous;
00718     bool           ticks_have_elapsed;
00719     bool           compare_update;
00720     app_timer_id_t timer_id_head_old;
00721 
00722     // Back up the previous known tick and previous list head
00723     ticks_previous    = m_ticks_latest;
00724     timer_id_head_old = m_timer_id_head;
00725 
00726     // Get number of elapsed ticks
00727     ticks_have_elapsed = elapsed_ticks_acquire(&ticks_elapsed);
00728 
00729     // Handle list deletions
00730     compare_update = list_deletions_handler();
00731 
00732     // Handle expired timers
00733     if (ticks_have_elapsed)
00734     {
00735         expired_timers_handler(ticks_elapsed, ticks_previous, &restart_list_head);
00736         compare_update = true;
00737     }
00738 
00739     // Handle list insertions
00740     if (list_insertions_handler(restart_list_head))
00741     {
00742         compare_update = true;
00743     }
00744 
00745     // Update compare register if necessary
00746     if (compare_update)
00747     {
00748         compare_reg_update(timer_id_head_old);
00749     }
00750 }
00751 
00752 
00753 /**@brief Function for enqueueing a new operations queue entry.
00754  *
00755  * @param[in]  p_user     User that the entry is to be enqueued for.
00756  * @param[in]  last_index Index of the next last index to be enqueued.
00757  */
00758 static void user_op_enque(timer_user_t * p_user, app_timer_id_t last_index)
00759 {
00760     p_user->last = last_index;
00761 }
00762 
00763 
00764 /**@brief Function for allocating a new operations queue entry.
00765  *
00766  * @param[in]  p_user       User that the entry is to be allocated for.
00767  * @param[out] p_last_index Index of the next last index to be enqueued.
00768  *
00769  * @return     Pointer to allocated queue entry, or NULL if queue is full.
00770  */
00771 static timer_user_op_t * user_op_alloc(timer_user_t * p_user, app_timer_id_t * p_last_index)
00772 {
00773     app_timer_id_t    last;
00774     timer_user_op_t * p_user_op;
00775 
00776     last = p_user->last + 1;
00777     if (last == p_user->user_op_queue_size)
00778     {
00779         // Overflow case.
00780         last = 0;
00781     }
00782     if (last == p_user->first)
00783     {
00784         // Queue is full.
00785         return NULL;
00786     }
00787 
00788     *p_last_index = last;
00789     p_user_op     = &p_user->p_user_op_queue[p_user->last];
00790 
00791     return p_user_op;
00792 }
00793 
00794 
00795 /**@brief Function for scheduling a Timer Start operation.
00796  *
00797  * @param[in]  user_id           Id of user calling this function.
00798  * @param[in]  timer_id          Id of timer to start.
00799  * @param[in]  timeout_initial   Time (in ticks) to first timer expiry.
00800  * @param[in]  timeout_periodic  Time (in ticks) between periodic expiries.
00801  * @param[in]  p_context         General purpose pointer. Will be passed to the timeout handler when
00802  *                               the timer expires.
00803  * @return     NRF_SUCCESS on success, otherwise an error code.
00804  */
00805 static uint32_t timer_start_op_schedule(timer_user_id_t user_id,
00806                                         app_timer_id_t  timer_id,
00807                                         uint32_t        timeout_initial,
00808                                         uint32_t        timeout_periodic,
00809                                         void *          p_context)
00810 {
00811     app_timer_id_t last_index;
00812 
00813     timer_user_op_t * p_user_op = user_op_alloc(&mp_users[user_id], &last_index);
00814     if (p_user_op == NULL)
00815     {
00816         return NRF_ERROR_NO_MEM;
00817     }
00818 
00819     p_user_op->op_type                              = TIMER_USER_OP_TYPE_START;
00820     p_user_op->timer_id                             = timer_id;
00821     p_user_op->params.start.ticks_at_start          = rtc1_counter_get();
00822     p_user_op->params.start.ticks_first_interval    = timeout_initial;
00823     p_user_op->params.start.ticks_periodic_interval = timeout_periodic;
00824     p_user_op->params.start.p_context               = p_context;
00825 
00826     user_op_enque(&mp_users[user_id], last_index);
00827 
00828     timer_list_handler_sched();
00829 
00830     return NRF_SUCCESS;
00831 }
00832 
00833 
00834 /**@brief Function for scheduling a Timer Stop operation.
00835  *
00836  * @param[in]  user_id    Id of user calling this function.
00837  * @param[in]  timer_id   Id of timer to stop.
00838  *
00839  * @return NRF_SUCCESS on successful scheduling a timer stop operation. NRF_ERROR_NO_MEM when there
00840  *         is no memory left to schedule the timer stop operation.
00841  */
00842 static uint32_t timer_stop_op_schedule(timer_user_id_t user_id, app_timer_id_t timer_id)
00843 {
00844     app_timer_id_t last_index;
00845 
00846     timer_user_op_t * p_user_op = user_op_alloc(&mp_users[user_id], &last_index);
00847     if (p_user_op == NULL)
00848     {
00849         return NRF_ERROR_NO_MEM;
00850     }
00851 
00852     p_user_op->op_type  = TIMER_USER_OP_TYPE_STOP;
00853     p_user_op->timer_id = timer_id;
00854 
00855     user_op_enque(&mp_users[user_id], last_index);
00856 
00857     timer_list_handler_sched();
00858 
00859     return NRF_SUCCESS;
00860 }
00861 
00862 
00863 /**@brief Function for scheduling a Timer Stop All operation.
00864  *
00865  * @param[in]  user_id    Id of user calling this function.
00866  */
00867 static uint32_t timer_stop_all_op_schedule(timer_user_id_t user_id)
00868 {
00869     app_timer_id_t last_index;
00870 
00871     timer_user_op_t * p_user_op = user_op_alloc(&mp_users[user_id], &last_index);
00872     if (p_user_op == NULL)
00873     {
00874         return NRF_ERROR_NO_MEM;
00875     }
00876 
00877     p_user_op->op_type  = TIMER_USER_OP_TYPE_STOP_ALL;
00878     p_user_op->timer_id = TIMER_NULL;
00879 
00880     user_op_enque(&mp_users[user_id], last_index);
00881 
00882     timer_list_handler_sched();
00883 
00884     return NRF_SUCCESS;
00885 }
00886 
00887 
00888 /**@brief Function for handling the RTC1 interrupt.
00889  *
00890  * @details Checks for timeouts, and executes timeout handlers for expired timers.
00891  */
00892 extern "C" void RTC1_IRQHandler(void)
00893 {
00894     // Clear all events (also unexpected ones)
00895     NRF_RTC1->EVENTS_COMPARE[0] = 0;
00896     NRF_RTC1->EVENTS_COMPARE[1] = 0;
00897     NRF_RTC1->EVENTS_COMPARE[2] = 0;
00898     NRF_RTC1->EVENTS_COMPARE[3] = 0;
00899     NRF_RTC1->EVENTS_TICK       = 0;
00900     NRF_RTC1->EVENTS_OVRFLW     = 0;
00901 
00902     // Check for expired timers
00903     timer_timeouts_check();
00904 }
00905 
00906 /**@brief Function for handling the SWI0 interrupt.
00907  *
00908  * @details Performs all updates to the timer list.
00909  */
00910 extern "C" void SWI0_IRQHandler(void)
00911 {
00912     timer_list_handler();
00913 }
00914 
00915 uint32_t app_timer_init(uint32_t                      prescaler,
00916                         uint8_t                       max_timers,
00917                         uint8_t                       op_queues_size,
00918                         void *                        p_buffer,
00919                         app_timer_evt_schedule_func_t evt_schedule_func)
00920 {
00921     int i;
00922 
00923     // Check that buffer is correctly aligned
00924     if (!is_word_aligned(p_buffer))
00925     {
00926         return NRF_ERROR_INVALID_PARAM;
00927     }
00928     // Check for NULL buffer
00929     if (p_buffer == NULL)
00930     {
00931         return NRF_ERROR_INVALID_PARAM;
00932     }
00933 
00934     // Stop RTC to prevent any running timers from expiring (in case of reinitialization)
00935     rtc1_stop();
00936 
00937     m_evt_schedule_func = evt_schedule_func;
00938 
00939     // Initialize timer node array
00940     m_node_array_size = max_timers;
00941     mp_nodes          = (timer_node_t *) p_buffer;
00942 
00943     for (i = 0; i < max_timers; i++)
00944     {
00945         mp_nodes[i].state      = STATE_FREE;
00946         mp_nodes[i].is_running = false;
00947     }
00948 
00949     // Skip timer node array
00950     p_buffer = &((uint8_t *)p_buffer)[max_timers * sizeof(timer_node_t)];
00951 
00952     // Initialize users array
00953     m_user_array_size = APP_TIMER_INT_LEVELS;
00954     mp_users          = (timer_user_t *) p_buffer;
00955 
00956     // Skip user array
00957     p_buffer = &((uint8_t *)p_buffer)[APP_TIMER_INT_LEVELS * sizeof(timer_user_t)];
00958 
00959     // Initialize operation queues
00960     for (i = 0; i < APP_TIMER_INT_LEVELS; i++)
00961     {
00962         timer_user_t * p_user = &mp_users[i];
00963 
00964         p_user->first              = 0;
00965         p_user->last               = 0;
00966         p_user->user_op_queue_size = op_queues_size;
00967         p_user->p_user_op_queue    = (timer_user_op_t *) p_buffer;
00968 
00969         // Skip operation queue
00970         p_buffer = &((uint8_t *)p_buffer)[op_queues_size * sizeof(timer_user_op_t)];
00971     }
00972 
00973     m_timer_id_head             = TIMER_NULL;
00974     m_ticks_elapsed_q_read_ind  = 0;
00975     m_ticks_elapsed_q_write_ind = 0;
00976 
00977     NVIC_ClearPendingIRQ(SWI0_IRQn);
00978     NVIC_SetPriority(SWI0_IRQn, SWI0_IRQ_PRI);
00979     NVIC_EnableIRQ(SWI0_IRQn);
00980 
00981     rtc1_init(prescaler);
00982 
00983     m_ticks_latest = rtc1_counter_get();
00984 
00985     return NRF_SUCCESS;
00986 }
00987 
00988 
00989 uint32_t app_timer_create(app_timer_id_t *            p_timer_id,
00990                           app_timer_mode_t            mode,
00991                           app_timer_timeout_handler_t timeout_handler)
00992 {
00993     int i;
00994 
00995     // Check state and parameters
00996     if (mp_nodes == NULL)
00997     {
00998         return NRF_ERROR_INVALID_STATE;
00999     }
01000     if (timeout_handler == NULL)
01001     {
01002         return NRF_ERROR_INVALID_PARAM;
01003     }
01004     if (p_timer_id == NULL)
01005     {
01006         return NRF_ERROR_INVALID_PARAM;
01007     }
01008 
01009     // Find free timer
01010     for (i = 0; i < m_node_array_size; i++)
01011     {
01012         if (mp_nodes[i].state == STATE_FREE)
01013         {
01014             mp_nodes[i].state             = STATE_ALLOCATED;
01015             mp_nodes[i].mode              = mode;
01016             mp_nodes[i].p_timeout_handler = timeout_handler;
01017 
01018             *p_timer_id = i;
01019             return NRF_SUCCESS;
01020         }
01021     }
01022 
01023     return NRF_ERROR_NO_MEM;
01024 }
01025 
01026 
01027 /**@brief Function for creating a timer user id from the current interrupt level.
01028  *
01029  * @return     Timer user id.
01030 */
01031 static timer_user_id_t user_id_get(void)
01032 {
01033     timer_user_id_t ret;
01034 
01035     STATIC_ASSERT(APP_TIMER_INT_LEVELS == 3);
01036 
01037     switch (current_int_priority_get())
01038     {
01039         case APP_IRQ_PRIORITY_HIGH:
01040             ret = APP_HIGH_USER_ID;
01041             break;
01042 
01043         case APP_IRQ_PRIORITY_LOW:
01044             ret = APP_LOW_USER_ID;
01045             break;
01046 
01047         default:
01048             ret = THREAD_MODE_USER_ID;
01049             break;
01050     }
01051 
01052     return ret;
01053 }
01054 
01055 
01056 uint32_t app_timer_start(app_timer_id_t timer_id, uint32_t timeout_ticks, void * p_context)
01057 {
01058     uint32_t timeout_periodic;
01059 
01060     // Check state and parameters
01061     if (mp_nodes == NULL)
01062     {
01063         return NRF_ERROR_INVALID_STATE;
01064     }
01065     if ((timer_id >= m_node_array_size) || (timeout_ticks < APP_TIMER_MIN_TIMEOUT_TICKS))
01066     {
01067         return NRF_ERROR_INVALID_PARAM;
01068     }
01069     if (mp_nodes[timer_id].state != STATE_ALLOCATED)
01070     {
01071         return NRF_ERROR_INVALID_STATE;
01072     }
01073 
01074     // Schedule timer start operation
01075     timeout_periodic = (mp_nodes[timer_id].mode == APP_TIMER_MODE_REPEATED) ? timeout_ticks : 0;
01076 
01077     return timer_start_op_schedule(user_id_get(),
01078                                    timer_id,
01079                                    timeout_ticks,
01080                                    timeout_periodic,
01081                                    p_context);
01082 }
01083 
01084 
01085 uint32_t app_timer_stop(app_timer_id_t timer_id)
01086 {
01087     // Check state and parameters
01088     if (mp_nodes == NULL)
01089     {
01090         return NRF_ERROR_INVALID_STATE;
01091     }
01092     if (timer_id >= m_node_array_size)
01093     {
01094         return NRF_ERROR_INVALID_PARAM;
01095     }
01096     if (mp_nodes[timer_id].state != STATE_ALLOCATED)
01097     {
01098         return NRF_ERROR_INVALID_STATE;
01099     }
01100 
01101     // Schedule timer stop operation
01102     return timer_stop_op_schedule(user_id_get(), timer_id);
01103 }
01104 
01105 
01106 uint32_t app_timer_stop_all(void)
01107 {
01108     // Check state
01109     if (mp_nodes == NULL)
01110     {
01111         return NRF_ERROR_INVALID_STATE;
01112     }
01113 
01114     return timer_stop_all_op_schedule(user_id_get());
01115 }
01116 
01117 
01118 uint32_t app_timer_cnt_get(uint32_t * p_ticks)
01119 {
01120     *p_ticks = rtc1_counter_get();
01121     return NRF_SUCCESS;
01122 }
01123 
01124 
01125 uint32_t app_timer_cnt_diff_compute(uint32_t   ticks_to,
01126                                     uint32_t   ticks_from,
01127                                     uint32_t * p_ticks_diff)
01128 {
01129     *p_ticks_diff = ticks_diff_get(ticks_to, ticks_from);
01130     return NRF_SUCCESS;
01131 }