changed low freq. clock source to IRC

Dependents:   BLE_ANCS_SDAPI_IRC

Fork of nRF51822 by Nordic Semiconductor

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