blob: 7766901981e46cf1aca409e7e771958526521245 [file] [log] [blame]
Benjamin Walsh456c6da2016-09-02 18:55:39 -04001/*
2 * Copyright (c) 1997-2016 Wind River Systems, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Allan Stephens45bfa372016-10-12 12:39:42 -050017#include <kernel.h>
Benjamin Walsh456c6da2016-09-02 18:55:39 -040018#include <misc/debug/object_tracing_common.h>
19#include <wait_q.h>
Benjamin Walsh456c6da2016-09-02 18:55:39 -040020
21/**
Allan Stephens45bfa372016-10-12 12:39:42 -050022 * @brief Handle expiration of a kernel timer object.
Benjamin Walsh456c6da2016-09-02 18:55:39 -040023 *
Allan Stephens45bfa372016-10-12 12:39:42 -050024 * @param t Timeout used by the timer.
Benjamin Walsh456c6da2016-09-02 18:55:39 -040025 *
26 * @return N/A
27 */
Allan Stephens45bfa372016-10-12 12:39:42 -050028static void timer_expiration_handler(struct _timeout *t)
Benjamin Walsh456c6da2016-09-02 18:55:39 -040029{
30 int key = irq_lock();
31 struct k_timer *timer = CONTAINER_OF(t, struct k_timer, timeout);
Allan Stephens45bfa372016-10-12 12:39:42 -050032 struct k_thread *pending_thread;
Benjamin Walsh456c6da2016-09-02 18:55:39 -040033
34 /* if the time is periodic, start it again */
35 if (timer->period > 0) {
Benjamin Walsh688973e2016-10-05 16:03:31 -040036 _add_timeout(NULL, &timer->timeout, &timer->wait_q,
Benjamin Walsh456c6da2016-09-02 18:55:39 -040037 timer->period);
38 }
39
Allan Stephens45bfa372016-10-12 12:39:42 -050040 /* update timer's status */
41 timer->status += 1;
42
43 /* invoke timer expiry function */
44 if (timer->expiry_fn) {
45 timer->expiry_fn(timer);
Benjamin Walsh456c6da2016-09-02 18:55:39 -040046 }
Allan Stephens45bfa372016-10-12 12:39:42 -050047 /*
48 * wake up the (only) thread waiting on the timer, if there is one;
49 * don't invoke _Swap() since the timeout ISR called us, not a thread
50 */
51 pending_thread = _unpend_first_thread(&timer->wait_q);
52 if (pending_thread) {
53 _ready_thread(pending_thread);
54 _set_thread_return_value(pending_thread, 0);
Benjamin Walsh456c6da2016-09-02 18:55:39 -040055 }
Allan Stephens45bfa372016-10-12 12:39:42 -050056
Benjamin Walsh456c6da2016-09-02 18:55:39 -040057 irq_unlock(key);
58}
59
60
Allan Stephens45bfa372016-10-12 12:39:42 -050061void k_timer_init(struct k_timer *timer,
62 void (*expiry_fn)(struct k_timer *),
63 void (*stop_fn)(struct k_timer *))
Benjamin Walsh456c6da2016-09-02 18:55:39 -040064{
Allan Stephens45bfa372016-10-12 12:39:42 -050065 timer->expiry_fn = expiry_fn;
66 timer->stop_fn = stop_fn;
67 timer->status = 0;
68
Benjamin Walsh456c6da2016-09-02 18:55:39 -040069 sys_dlist_init(&timer->wait_q);
Benjamin Walsh055262c2016-10-05 17:16:01 -040070 _init_timeout(&timer->timeout, timer_expiration_handler);
Benjamin Walsh456c6da2016-09-02 18:55:39 -040071 SYS_TRACING_OBJ_INIT(micro_timer, timer);
Allan Stephens45bfa372016-10-12 12:39:42 -050072
73 timer->_legacy_data = NULL;
Benjamin Walsh456c6da2016-09-02 18:55:39 -040074}
75
76
Allan Stephens45bfa372016-10-12 12:39:42 -050077void k_timer_start(struct k_timer *timer, int32_t duration, int32_t period)
Benjamin Walsh456c6da2016-09-02 18:55:39 -040078{
79 __ASSERT(duration >= 0 && period >= 0 &&
80 (duration != 0 || period != 0), "invalid parameters\n");
81
82 unsigned int key = irq_lock();
83
84 if (timer->timeout.delta_ticks_from_prev != -1) {
Benjamin Walsh7caef452016-10-05 12:55:17 -040085 _abort_timeout(&timer->timeout);
Benjamin Walsh456c6da2016-09-02 18:55:39 -040086 }
87
88 timer->period = _ms_to_ticks(period);
Benjamin Walsh688973e2016-10-05 16:03:31 -040089 _add_timeout(NULL, &timer->timeout, &timer->wait_q,
Benjamin Walsh456c6da2016-09-02 18:55:39 -040090 _ms_to_ticks(duration));
Allan Stephens45bfa372016-10-12 12:39:42 -050091 timer->status = 0;
Benjamin Walsh456c6da2016-09-02 18:55:39 -040092 irq_unlock(key);
93}
94
95
Benjamin Walsh456c6da2016-09-02 18:55:39 -040096void k_timer_stop(struct k_timer *timer)
97{
98 __ASSERT(!_is_in_isr(), "");
99
100 int key = irq_lock();
Allan Stephens45bfa372016-10-12 12:39:42 -0500101 int stopped = _abort_timeout(&timer->timeout);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400102
103 irq_unlock(key);
104
Allan Stephens45bfa372016-10-12 12:39:42 -0500105 if (stopped == -1) {
106 return;
107 }
108
109 if (timer->stop_fn) {
110 timer->stop_fn(timer);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400111 }
112
113 key = irq_lock();
Benjamin Walshb7ef0cb2016-10-05 17:32:01 -0400114 struct k_thread *pending_thread = _unpend_first_thread(&timer->wait_q);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400115
116 if (pending_thread) {
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400117 _ready_thread(pending_thread);
118 }
119
Allan Stephens45bfa372016-10-12 12:39:42 -0500120 if (_is_in_isr()) {
121 irq_unlock(key);
122 } else {
123 _reschedule_threads(key);
124 }
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400125}
126
127
Allan Stephens45bfa372016-10-12 12:39:42 -0500128uint32_t k_timer_status_get(struct k_timer *timer)
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400129{
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400130 unsigned int key = irq_lock();
Allan Stephens45bfa372016-10-12 12:39:42 -0500131 uint32_t result = timer->status;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400132
Allan Stephens45bfa372016-10-12 12:39:42 -0500133 timer->status = 0;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400134 irq_unlock(key);
Allan Stephens45bfa372016-10-12 12:39:42 -0500135
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400136 return result;
137}
138
139
Allan Stephens45bfa372016-10-12 12:39:42 -0500140uint32_t k_timer_status_sync(struct k_timer *timer)
141{
142 __ASSERT(!_is_in_isr(), "");
143
144 unsigned int key = irq_lock();
145 uint32_t result = timer->status;
146
147 if (result == 0) {
148 if (timer->timeout.delta_ticks_from_prev != -1) {
149 /* wait for timer to expire or stop */
150 _pend_current_thread(&timer->wait_q, K_FOREVER);
151 _Swap(key);
152
153 /* get updated timer status */
154 key = irq_lock();
155 result = timer->status;
156 } else {
157 /* timer is already stopped */
158 }
159 } else {
160 /* timer has already expired at least once */
161 }
162
163 timer->status = 0;
164 irq_unlock(key);
165
166 return result;
167}
168
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400169
170int32_t k_timer_remaining_get(struct k_timer *timer)
171{
172 unsigned int key = irq_lock();
173 int32_t remaining_ticks;
174 sys_dlist_t *timeout_q = &_nanokernel.timeout_q;
175
176 if (timer->timeout.delta_ticks_from_prev == -1) {
177 remaining_ticks = 0;
178 } else {
179 /*
Allan Stephens45bfa372016-10-12 12:39:42 -0500180 * compute remaining ticks by walking the timeout list
181 * and summing up the various tick deltas involved
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400182 */
183 struct _timeout *t =
184 (struct _timeout *)sys_dlist_peek_head(timeout_q);
185
186 remaining_ticks = t->delta_ticks_from_prev;
187 while (t != &timer->timeout) {
188 t = (struct _timeout *)sys_dlist_peek_next(timeout_q,
189 &t->node);
190 remaining_ticks += t->delta_ticks_from_prev;
191 }
192 }
193
194 irq_unlock(key);
195 return _ticks_to_ms(remaining_ticks);
196}