1 /*
2 # Copyright (C) 2024 HiHope Open Source Organization .
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 <stdint.h>
17 #include <errno.h>
18 #include <time.h>
19 #include <signal.h>
20 #include <unistd.h>
21 #include <los_hwi.h>
22 #include <los_swtmr.h>
23 #include <los_swtmr_pri.h>
24
25 #ifndef STATIC
26 #define STATIC static
27 #endif
28
29 #define OS_SYS_NS_PER_US 1000
30 #define OS_SYS_NS_PER_SECOND 1000000000
31 #define OS_SYS_US_PER_SECOND 1000000
32 #define OS_SYS_MS_PER_SECOND 1000
33
ValidTimerID(UINT16 swtmrID)34 STATIC INLINE BOOL ValidTimerID(UINT16 swtmrID)
35 {
36 /* check timer id */
37 return (swtmrID < LOSCFG_BASE_CORE_SWTMR_LIMIT);
38 }
39
40 /* internal functions */
ValidTimeSpec(const struct timespec * tp)41 STATIC INLINE BOOL ValidTimeSpec(const struct timespec *tp)
42 {
43 /* Fail a NULL pointer */
44 if (tp == NULL) {
45 return FALSE;
46 }
47
48 /* Fail illegal nanosecond values */
49 if ((tp->tv_nsec < 0) || (tp->tv_nsec >= OS_SYS_NS_PER_SECOND) || (tp->tv_sec < 0)) {
50 return FALSE;
51 }
52
53 return TRUE;
54 }
55
OsTimeSpec2Tick(const struct timespec * tp)56 STATIC INLINE UINT32 OsTimeSpec2Tick(const struct timespec *tp)
57 {
58 UINT64 tick, ns;
59
60 ns = (UINT64)tp->tv_sec * OS_SYS_NS_PER_SECOND + tp->tv_nsec;
61 /* Round up for ticks */
62 tick = (ns * LOSCFG_BASE_CORE_TICK_PER_SECOND + (OS_SYS_NS_PER_SECOND - 1)) / OS_SYS_NS_PER_SECOND;
63 if (tick > LOS_WAIT_FOREVER) {
64 tick = LOS_WAIT_FOREVER;
65 }
66 return (UINT32)tick;
67 }
68
OsTick2TimeSpec(struct timespec * tp,UINT32 tick)69 STATIC INLINE VOID OsTick2TimeSpec(struct timespec *tp, UINT32 tick)
70 {
71 UINT64 ns = ((UINT64)tick * OS_SYS_NS_PER_SECOND) / LOSCFG_BASE_CORE_TICK_PER_SECOND;
72 tp->tv_sec = (time_t)(ns / OS_SYS_NS_PER_SECOND);
73 tp->tv_nsec = (long)(ns % OS_SYS_NS_PER_SECOND);
74 }
75
nanosleep(const struct timespec * rqtp,struct timespec * rmtp)76 int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
77 {
78 UINT64 nseconds;
79 UINT64 tick;
80 UINT32 ret;
81 const UINT32 nsPerTick = OS_SYS_NS_PER_SECOND / LOSCFG_BASE_CORE_TICK_PER_SECOND;
82
83 if (!ValidTimeSpec(rqtp)) {
84 errno = EINVAL;
85 return -1;
86 }
87
88 nseconds = (UINT64)rqtp->tv_sec * OS_SYS_NS_PER_SECOND + rqtp->tv_nsec;
89
90 tick = (nseconds + nsPerTick - 1) / nsPerTick; // Round up for ticks
91
92 if (tick >= UINT32_MAX) {
93 errno = EINVAL;
94 return -1;
95 }
96
97 /* PS: skip the first tick because it is NOT a full tick. */
98 ret = LOS_TaskDelay(tick ? (UINT32)(tick + 1) : 0);
99 if (ret == LOS_OK || ret == LOS_ERRNO_TSK_YIELD_NOT_ENOUGH_TASK) {
100 if (rmtp) {
101 rmtp->tv_sec = rmtp->tv_nsec = 0;
102 }
103 return 0;
104 }
105
106 /* sleep in interrupt context or in task sched lock state */
107 errno = EPERM;
108 return -1;
109 }
110
timer_create(clockid_t clockID,struct sigevent * restrict evp,timer_t * restrict timerID)111 int timer_create(clockid_t clockID, struct sigevent *restrict evp, timer_t *restrict timerID)
112 {
113 UINT32 ret;
114 UINT16 swtmrID;
115
116 if (!timerID || (clockID != CLOCK_REALTIME)) {
117 errno = EINVAL;
118 return -1;
119 }
120
121 if (!evp || evp->sigev_notify != SIGEV_THREAD || evp->sigev_notify_attributes) {
122 errno = ENOTSUP;
123 return -1;
124 }
125
126 ret = LOS_SwtmrCreate(1, LOS_SWTMR_MODE_ONCE, (SWTMR_PROC_FUNC)evp->sigev_notify_function,
127 &swtmrID, (UINT32)(UINTPTR)evp->sigev_value.sival_ptr);
128 if (ret != LOS_OK) {
129 errno = (ret == LOS_ERRNO_SWTMR_MAXSIZE) ? EAGAIN : EINVAL;
130 return -1;
131 }
132
133 *timerID = (timer_t)(UINTPTR)swtmrID;
134 return 0;
135 }
136
timer_delete(timer_t timerID)137 int timer_delete(timer_t timerID)
138 {
139 UINT16 swtmrID = (UINT16)(UINTPTR)timerID;
140
141 if (!ValidTimerID(swtmrID)) {
142 errno = EINVAL;
143 return -1;
144 }
145
146 if (LOS_SwtmrDelete(swtmrID) != LOS_OK) {
147 errno = EINVAL;
148 return -1;
149 }
150
151 return 0;
152 }
153
timer_settime(timer_t timerID,int flags,const struct itimerspec * restrict value,struct itimerspec * restrict oldValue)154 int timer_settime(timer_t timerID, int flags,
155 const struct itimerspec *restrict value,
156 struct itimerspec *restrict oldValue)
157 {
158 UINT32 intSave;
159 UINT16 swtmrID = (UINT16)(UINTPTR)timerID;
160 SWTMR_CTRL_S *swtmr = NULL;
161 UINT32 interval, expiry, ret;
162
163 if (flags != 0) {
164 /* flags not supported currently */
165 errno = ENOSYS;
166 return -1;
167 }
168
169 if (value == NULL || !ValidTimerID(swtmrID)) {
170 errno = EINVAL;
171 return -1;
172 }
173
174 if (!ValidTimeSpec(&value->it_value) || !ValidTimeSpec(&value->it_interval)) {
175 errno = EINVAL;
176 return -1;
177 }
178
179 expiry = OsTimeSpec2Tick(&value->it_value);
180 interval = OsTimeSpec2Tick(&value->it_interval);
181 /* if specified interval, it must be same with expiry due to the limitation of liteos-m */
182 if (interval && interval != expiry) {
183 errno = ENOTSUP;
184 return -1;
185 }
186
187 if (oldValue) {
188 (VOID)timer_gettime(timerID, oldValue);
189 }
190
191 ret = LOS_SwtmrStop(swtmrID);
192 if ((ret != LOS_OK) && (ret != LOS_ERRNO_SWTMR_NOT_STARTED)) {
193 errno = EINVAL;
194 return -1;
195 }
196
197 intSave = LOS_IntLock();
198 swtmr = OS_SWT_FROM_SID(swtmrID);
199 swtmr->ucMode = (interval ? LOS_SWTMR_MODE_PERIOD : LOS_SWTMR_MODE_NO_SELFDELETE);
200 swtmr->uwInterval = (interval ? interval : expiry);
201
202 LOS_IntRestore(intSave);
203
204 if ((value->it_value.tv_sec == 0) && (value->it_value.tv_nsec == 0)) {
205 /*
206 * 1) when expiry is 0, means timer should be stopped.
207 * 2) If timer is ticking, stopping timer is already done before.
208 * 3) If timer is created but not ticking, return 0 as well.
209 */
210 return 0;
211 }
212
213 if (LOS_SwtmrStart(swtmr->usTimerID) != LOS_OK) {
214 errno = EINVAL;
215 return -1;
216 }
217
218 return 0;
219 }
220
timer_gettime(timer_t timerID,struct itimerspec * value)221 int timer_gettime(timer_t timerID, struct itimerspec *value)
222 {
223 UINT32 tick = 0;
224 SWTMR_CTRL_S *swtmr = NULL;
225 UINT16 swtmrID = (UINT16)(UINTPTR)timerID;
226 UINT32 ret;
227
228 if ((value == NULL) || !ValidTimerID(swtmrID)) {
229 errno = EINVAL;
230 return -1;
231 }
232
233 swtmr = OS_SWT_FROM_SID(swtmrID);
234
235 /* get expire time */
236 ret = LOS_SwtmrTimeGet(swtmr->usTimerID, &tick);
237 if ((ret != LOS_OK) && (ret != LOS_ERRNO_SWTMR_NOT_STARTED)) {
238 errno = EINVAL;
239 return -1;
240 }
241
242 OsTick2TimeSpec(&value->it_value, tick);
243 OsTick2TimeSpec(&value->it_interval, (swtmr->ucMode == LOS_SWTMR_MODE_ONCE) ? 0 : swtmr->uwInterval);
244 return 0;
245 }
246
timer_getoverrun(timer_t timerID)247 int timer_getoverrun(timer_t timerID)
248 {
249 UINT16 swtmrID = (UINT16)(UINTPTR)timerID;
250
251 if (!ValidTimerID(swtmrID)) {
252 errno = EINVAL;
253 return -1;
254 }
255
256 errno = ENOSYS;
257 return -1;
258 }
259