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 timer->name = (attr->name == NULL) ? init_timer_attrs.name : attr->name;
71
72 return (osTimerId_t)timer;
73 }
74
75 /**
76 * @brief Start or restart a Timer
77 */
osTimerStart(osTimerId_t timer_id,uint32_t ticks)78 osStatus_t osTimerStart(osTimerId_t timer_id, uint32_t ticks)
79 {
80 struct cmsis_rtos_timer_cb *timer = (struct cmsis_rtos_timer_cb *)timer_id;
81
82 if (timer == NULL) {
83 return osErrorParameter;
84 }
85
86 if (k_is_in_isr()) {
87 return osErrorISR;
88 }
89
90 if (timer->type == osTimerOnce) {
91 k_timer_start(&timer->z_timer, K_TICKS(ticks), K_NO_WAIT);
92 } else if (timer->type == osTimerPeriodic) {
93 k_timer_start(&timer->z_timer, K_TICKS(ticks), K_TICKS(ticks));
94 }
95
96 timer->status = ACTIVE;
97 return osOK;
98 }
99
100 /**
101 * @brief Stop the Timer
102 */
osTimerStop(osTimerId_t timer_id)103 osStatus_t osTimerStop(osTimerId_t timer_id)
104 {
105 struct cmsis_rtos_timer_cb *timer = (struct cmsis_rtos_timer_cb *)timer_id;
106
107 if (timer == NULL) {
108 return osErrorParameter;
109 }
110
111 if (k_is_in_isr()) {
112 return osErrorISR;
113 }
114
115 if (timer->status == NOT_ACTIVE) {
116 return osErrorResource;
117 }
118
119 k_timer_stop(&timer->z_timer);
120 timer->status = NOT_ACTIVE;
121 return osOK;
122 }
123
124 /**
125 * @brief Delete the timer that was created by osTimerCreate
126 */
osTimerDelete(osTimerId_t timer_id)127 osStatus_t osTimerDelete(osTimerId_t timer_id)
128 {
129 struct cmsis_rtos_timer_cb *timer = (struct cmsis_rtos_timer_cb *)timer_id;
130
131 if (timer == NULL) {
132 return osErrorParameter;
133 }
134
135 if (k_is_in_isr()) {
136 return osErrorISR;
137 }
138
139 if (timer->status == ACTIVE) {
140 k_timer_stop(&timer->z_timer);
141 timer->status = NOT_ACTIVE;
142 }
143
144 if (timer->is_cb_dynamic_allocation) {
145 k_mem_slab_free(&cmsis_rtos_timer_cb_slab, (void *)timer);
146 }
147 return osOK;
148 }
149
150 /**
151 * @brief Get name of a timer.
152 * This function may be called from Interrupt Service Routines.
153 */
osTimerGetName(osTimerId_t timer_id)154 const char *osTimerGetName(osTimerId_t timer_id)
155 {
156 struct cmsis_rtos_timer_cb *timer = (struct cmsis_rtos_timer_cb *)timer_id;
157
158 if (timer == NULL) {
159 return NULL;
160 }
161 return timer->name;
162 }
163
164 /**
165 * @brief Check if a timer is running.
166 */
osTimerIsRunning(osTimerId_t timer_id)167 uint32_t osTimerIsRunning(osTimerId_t timer_id)
168 {
169 struct cmsis_rtos_timer_cb *timer = (struct cmsis_rtos_timer_cb *)timer_id;
170
171 if (k_is_in_isr() || (timer == NULL)) {
172 return 0;
173 }
174
175 return !(!(k_timer_remaining_get(&timer->z_timer)));
176 }
177