1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/portability/cmsis_types.h>
9 #include <string.h>
10 
11 #define ACTIVE     1
12 #define NOT_ACTIVE 0
13 
14 static void zephyr_timer_wrapper(struct k_timer *timer);
15 
16 K_MEM_SLAB_DEFINE(cmsis_rtos_timer_cb_slab, sizeof(struct cmsis_rtos_timer_cb),
17 		  CONFIG_CMSIS_V2_TIMER_MAX_COUNT, 4);
18 
19 static const osTimerAttr_t init_timer_attrs = {
20 	.name = "ZephyrTimer",
21 	.attr_bits = 0,
22 	.cb_mem = NULL,
23 	.cb_size = 0,
24 };
25 
zephyr_timer_wrapper(struct k_timer * timer)26 static void zephyr_timer_wrapper(struct k_timer *timer)
27 {
28 	struct cmsis_rtos_timer_cb *cm_timer;
29 
30 	cm_timer = CONTAINER_OF(timer, struct cmsis_rtos_timer_cb, z_timer);
31 	(cm_timer->callback_function)(cm_timer->arg);
32 }
33 
34 /**
35  * @brief Create a Timer
36  */
osTimerNew(osTimerFunc_t func,osTimerType_t type,void * argument,const osTimerAttr_t * attr)37 osTimerId_t osTimerNew(osTimerFunc_t func, osTimerType_t type, void *argument,
38 		       const osTimerAttr_t *attr)
39 {
40 	struct cmsis_rtos_timer_cb *timer;
41 
42 	if (type != osTimerOnce && type != osTimerPeriodic) {
43 		return NULL;
44 	}
45 
46 	if (k_is_in_isr()) {
47 		return NULL;
48 	}
49 
50 	if (attr == NULL) {
51 		attr = &init_timer_attrs;
52 	}
53 
54 	if (attr->cb_mem != NULL) {
55 		__ASSERT(attr->cb_size == sizeof(struct cmsis_rtos_timer_cb), "Invalid cb_size\n");
56 		timer = (struct cmsis_rtos_timer_cb *)attr->cb_mem;
57 	} else if (k_mem_slab_alloc(&cmsis_rtos_timer_cb_slab, (void **)&timer, K_MSEC(100)) != 0) {
58 		return NULL;
59 	}
60 	(void)memset(timer, 0, sizeof(struct cmsis_rtos_timer_cb));
61 	timer->is_cb_dynamic_allocation = attr->cb_mem == NULL;
62 
63 	timer->callback_function = func;
64 	timer->arg = argument;
65 	timer->type = type;
66 	timer->status = NOT_ACTIVE;
67 
68 	k_timer_init(&timer->z_timer, zephyr_timer_wrapper, NULL);
69 
70 	if (attr->name == NULL) {
71 		strncpy(timer->name, init_timer_attrs.name, sizeof(timer->name) - 1);
72 	} else {
73 		strncpy(timer->name, attr->name, sizeof(timer->name) - 1);
74 	}
75 
76 	return (osTimerId_t)timer;
77 }
78 
79 /**
80  * @brief Start or restart a Timer
81  */
osTimerStart(osTimerId_t timer_id,uint32_t ticks)82 osStatus_t osTimerStart(osTimerId_t timer_id, uint32_t ticks)
83 {
84 	struct cmsis_rtos_timer_cb *timer = (struct cmsis_rtos_timer_cb *)timer_id;
85 
86 	if (timer == NULL) {
87 		return osErrorParameter;
88 	}
89 
90 	if (k_is_in_isr()) {
91 		return osErrorISR;
92 	}
93 
94 	if (timer->type == osTimerOnce) {
95 		k_timer_start(&timer->z_timer, K_TICKS(ticks), K_NO_WAIT);
96 	} else if (timer->type == osTimerPeriodic) {
97 		k_timer_start(&timer->z_timer, K_TICKS(ticks), K_TICKS(ticks));
98 	}
99 
100 	timer->status = ACTIVE;
101 	return osOK;
102 }
103 
104 /**
105  * @brief Stop the Timer
106  */
osTimerStop(osTimerId_t timer_id)107 osStatus_t osTimerStop(osTimerId_t timer_id)
108 {
109 	struct cmsis_rtos_timer_cb *timer = (struct cmsis_rtos_timer_cb *)timer_id;
110 
111 	if (timer == NULL) {
112 		return osErrorParameter;
113 	}
114 
115 	if (k_is_in_isr()) {
116 		return osErrorISR;
117 	}
118 
119 	if (timer->status == NOT_ACTIVE) {
120 		return osErrorResource;
121 	}
122 
123 	k_timer_stop(&timer->z_timer);
124 	timer->status = NOT_ACTIVE;
125 	return osOK;
126 }
127 
128 /**
129  * @brief Delete the timer that was created by osTimerCreate
130  */
osTimerDelete(osTimerId_t timer_id)131 osStatus_t osTimerDelete(osTimerId_t timer_id)
132 {
133 	struct cmsis_rtos_timer_cb *timer = (struct cmsis_rtos_timer_cb *)timer_id;
134 
135 	if (timer == NULL) {
136 		return osErrorParameter;
137 	}
138 
139 	if (k_is_in_isr()) {
140 		return osErrorISR;
141 	}
142 
143 	if (timer->status == ACTIVE) {
144 		k_timer_stop(&timer->z_timer);
145 		timer->status = NOT_ACTIVE;
146 	}
147 
148 	if (timer->is_cb_dynamic_allocation) {
149 		k_mem_slab_free(&cmsis_rtos_timer_cb_slab, (void *)timer);
150 	}
151 	return osOK;
152 }
153 
154 /**
155  * @brief Get name of a timer.
156  */
osTimerGetName(osTimerId_t timer_id)157 const char *osTimerGetName(osTimerId_t timer_id)
158 {
159 	struct cmsis_rtos_timer_cb *timer = (struct cmsis_rtos_timer_cb *)timer_id;
160 
161 	if (k_is_in_isr() || (timer == NULL)) {
162 		return NULL;
163 	}
164 
165 	return timer->name;
166 }
167 
168 /**
169  * @brief Check if a timer is running.
170  */
osTimerIsRunning(osTimerId_t timer_id)171 uint32_t osTimerIsRunning(osTimerId_t timer_id)
172 {
173 	struct cmsis_rtos_timer_cb *timer = (struct cmsis_rtos_timer_cb *)timer_id;
174 
175 	if (k_is_in_isr() || (timer == NULL)) {
176 		return 0;
177 	}
178 
179 	return !(!(k_timer_remaining_get(&timer->z_timer)));
180 }
181