1 /*
2 * Copyright (c) 2022 Winner Microelectronics Co., Ltd. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <string.h>
17 #include "wm_mem.h"
18 #include "wm_wl_task.h"
19 #include "wm_wl_timers.h"
20
21 struct tls_timeo {
22 struct tls_timeo *next;
23 u32 time;
24 tls_timeout_handler h;
25 void *arg;
26 };
27
28 /** The one and only timeout list */
29 struct tls_timeo *next_timeout[TLS_TIMEO_ALL_COUONT];
30
31 /**
32 * @brief Wait (forever) for a message to arrive in an mbox.
33 * While waiting, timeouts are processed
34 *
35 * @param[in] timeo_assigned timer NO. by assigned
36 * @param[in] mbox the mbox to fetch the message from
37 * @param[out] **msg the place to store the message
38 *
39 * @return None
40 *
41 * @note None
42 */
tls_timeouts_mbox_fetch_p(u8 timeo_assigned,tls_mbox_t mbox,void ** msg)43 void tls_timeouts_mbox_fetch_p(u8 timeo_assigned, tls_mbox_t mbox, void **msg)
44 {
45 u32 time_needed;
46 struct tls_timeo *tmptimeout;
47 tls_timeout_handler handler;
48 void *arg;
49
50 struct tls_timeo **timeo = &next_timeout[timeo_assigned];
51
52 again:
53 if (!(*timeo)) {
54 time_needed = tls_arch_mbox_fetch(mbox, msg, 0);
55 } else {
56 if ((*timeo)->time > 0) {
57 time_needed = tls_arch_mbox_fetch(mbox, msg, (*timeo)->time);
58 } else {
59 time_needed = SYS_ARCH_TIMEOUT;
60 }
61
62 if (time_needed == SYS_ARCH_TIMEOUT) {
63 /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
64 could be fetched. We should now call the timeout handler and
65 deallocate the memory allocated for the timeout. */
66 tmptimeout = *timeo;
67 *timeo = tmptimeout -> next;
68 handler = tmptimeout -> h;
69 arg = tmptimeout -> arg;
70 tls_mem_free(tmptimeout);
71 if (handler != NULL) {
72 handler(arg);
73 }
74
75 /* We try again to fetch a message from the mbox. */
76 goto again;
77 } else {
78 /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
79 occured. The time variable is set to the number of
80 milliseconds we waited for the message. */
81 if (time_needed < (*timeo)->time) {
82 (*timeo)->time -= time_needed;
83 } else {
84 (*timeo)->time = 0;
85 }
86 }
87 }
88 }
89
90 /**
91 * @brief create a one-shot timer (aka timeout)
92 *
93 * @param[in] timeo_assigned timer NO. by assigned
94 * @param[in] msecs time in milliseconds after that the timer should expire
95 * @param[in] handler callback function that would be called by the timeout
96 * @param[in] *arg callback argument that would be passed to handler
97 *
98 * @return None
99 *
100 * @note while waiting for a message using sys_timeouts_mbox_fetch()
101 */
tls_timeout_p(u8 timeo_assigned,u32 msecs,tls_timeout_handler handler,void * arg)102 void tls_timeout_p(u8 timeo_assigned, u32 msecs, tls_timeout_handler handler, void *arg)
103 {
104 struct tls_timeo *timeout, *t;
105 struct tls_timeo **timeo = &next_timeout[timeo_assigned];
106
107 timeout = (struct tls_timeo *)tls_mem_alloc(sizeof(struct tls_timeo));
108 if (timeout == NULL) {
109 return;
110 }
111 timeout->next = NULL;
112 timeout->h = handler;
113 timeout->arg = arg;
114 timeout->time = msecs;
115
116 if (*timeo == NULL) {
117 *timeo = timeout;
118 return;
119 }
120
121 if ((*timeo)->time > msecs) {
122 (*timeo)->time -= msecs;
123 timeout->next = *timeo;
124 *timeo = timeout;
125 } else {
126 for (t = *timeo; t != NULL; t = t->next) {
127 timeout->time -= t->time;
128 if (t->next == NULL || t->next->time > timeout->time) {
129 if (t->next != NULL) {
130 t->next->time -= timeout->time;
131 }
132 timeout->next = t->next;
133 t->next = timeout;
134 break;
135 }
136 }
137 }
138 }
139
140 /**
141 * @brief Go through timeout list (for this task only) and remove the first
142 * matching entry, even though the timeout has not triggered yet
143 *
144 * @param[in] timeo_assigned timer NO. by assigned
145 * @param[in] handler callback function that would be called by the timeout
146 * @param[in] *arg callback argument that would be passed to handler
147 *
148 * @return None
149 *
150 * @note None
151 */
tls_untimeout_p(u8 timeo_assigned,tls_timeout_handler handler,void * arg)152 void tls_untimeout_p(u8 timeo_assigned, tls_timeout_handler handler, void *arg)
153 {
154 struct tls_timeo *prev_t, *t;
155 struct tls_timeo **timeo = &next_timeout[timeo_assigned];
156
157 if (*timeo == NULL) {
158 return;
159 }
160
161 for (t = *timeo, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
162 if ((t->h == handler) && (t->arg == arg)) {
163 /* We have a match */
164 /* Unlink from previous in list */
165 if (prev_t == NULL) {
166 *timeo = t->next;
167 } else {
168 prev_t->next = t->next;
169 }
170 /* If not the last one, add time of this one back to next */
171 if (t->next != NULL) {
172 t->next->time += t->time;
173 }
174 tls_mem_free(t);
175 return;
176 }
177 }
178 return;
179 }
180
181 /**
182 * @brief timer initialized
183 *
184 * @param None
185 *
186 * @return None
187 *
188 * @note None
189 */
tls_wl_timer_init(void)190 s8 tls_wl_timer_init(void)
191 {
192 memset(next_timeout, 0, sizeof(struct tls_timeo *) *TLS_TIMEO_ALL_COUONT);
193 return 0;
194 }
195