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