1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <cmsis_os.h>
9
10 #define MAX_VALID_SIGNAL_VAL ((1 << osFeature_Signals) - 1)
11
k_thread_other_custom_data_get(struct k_thread * thread_id)12 void *k_thread_other_custom_data_get(struct k_thread *thread_id)
13 {
14 return thread_id->custom_data;
15 }
16
17 /**
18 * @brief Set the specified Signal Flags of an active thread.
19 */
osSignalSet(osThreadId thread_id,int32_t signals)20 int32_t osSignalSet(osThreadId thread_id, int32_t signals)
21 {
22 int sig, key;
23
24 if ((thread_id == NULL) || (!signals) ||
25 (signals & 0x80000000) || (signals > MAX_VALID_SIGNAL_VAL)) {
26 return 0x80000000;
27 }
28
29 osThreadDef_t *thread_def =
30 (osThreadDef_t *)k_thread_other_custom_data_get(
31 (struct k_thread *)thread_id);
32
33 key = irq_lock();
34 sig = thread_def->signal_results;
35 thread_def->signal_results |= signals;
36 irq_unlock(key);
37
38 k_poll_signal_raise(thread_def->poll_signal, signals);
39
40 return sig;
41 }
42
43 /**
44 * @brief Clear the specified Signal Flags of an active thread.
45 */
osSignalClear(osThreadId thread_id,int32_t signals)46 int32_t osSignalClear(osThreadId thread_id, int32_t signals)
47 {
48 int sig, key;
49
50 if (k_is_in_isr() || (thread_id == NULL) || (!signals) ||
51 (signals & 0x80000000) || (signals > MAX_VALID_SIGNAL_VAL)) {
52 return 0x80000000;
53 }
54
55 osThreadDef_t *thread_def =
56 (osThreadDef_t *)k_thread_other_custom_data_get(
57 (struct k_thread *)thread_id);
58
59 key = irq_lock();
60 sig = thread_def->signal_results;
61 thread_def->signal_results &= ~(signals);
62 irq_unlock(key);
63
64 return sig;
65 }
66
67 /**
68 * @brief Wait for one or more Signal Flags to become signalled for the
69 * current running thread.
70 */
osSignalWait(int32_t signals,uint32_t millisec)71 osEvent osSignalWait(int32_t signals, uint32_t millisec)
72 {
73 int retval, key;
74 osEvent evt = {0};
75 uint32_t time_delta_ms, timeout = millisec;
76 uint64_t time_stamp_start, hwclk_cycles_delta, time_delta_ns;
77
78 if (k_is_in_isr()) {
79 evt.status = osErrorISR;
80 return evt;
81 }
82
83 /* Check if signals is within the permitted range */
84 if ((signals & 0x80000000) || (signals > MAX_VALID_SIGNAL_VAL)) {
85 evt.status = osErrorValue;
86 return evt;
87 }
88
89 osThreadDef_t *thread_def = k_thread_custom_data_get();
90
91 for (;;) {
92
93 time_stamp_start = (uint64_t)k_cycle_get_32();
94
95 switch (millisec) {
96 case 0:
97 retval = k_poll(thread_def->poll_event, 1, K_NO_WAIT);
98 break;
99 case osWaitForever:
100 retval = k_poll(thread_def->poll_event, 1, K_FOREVER);
101 break;
102 default:
103 retval = k_poll(thread_def->poll_event, 1,
104 K_MSEC(timeout));
105 break;
106 }
107
108 switch (retval) {
109 case 0:
110 evt.status = osEventSignal;
111 break;
112 case -EAGAIN:
113 if (millisec == 0U) {
114 evt.status = osOK;
115 } else {
116 evt.status = osEventTimeout;
117 }
118 return evt;
119 default:
120 evt.status = osErrorValue;
121 return evt;
122 }
123
124 __ASSERT(thread_def->poll_event->state
125 == K_POLL_STATE_SIGNALED,
126 "event state not signalled!");
127 __ASSERT(thread_def->poll_event->signal->signaled == 1,
128 "event signaled is not 1");
129
130 /* Reset the states to facilitate the next trigger */
131 thread_def->poll_event->signal->signaled = 0;
132 thread_def->poll_event->state = K_POLL_STATE_NOT_READY;
133
134 /* Check if all events we are waiting on have been signalled */
135 if ((thread_def->signal_results & signals) == signals) {
136 break;
137 }
138
139 /* If we need to wait on more signals, we need to adjust the
140 * timeout value accordingly based on the time that has
141 * already elapsed.
142 */
143 hwclk_cycles_delta = (uint64_t)k_cycle_get_32() - time_stamp_start;
144 time_delta_ns =
145 (uint32_t)k_cyc_to_ns_floor64(hwclk_cycles_delta);
146 time_delta_ms = (uint32_t)time_delta_ns/NSEC_PER_MSEC;
147
148 if (timeout > time_delta_ms) {
149 timeout -= time_delta_ms;
150 } else {
151 timeout = 0U;
152 }
153 }
154
155 evt.value.signals = thread_def->signal_results;
156
157 /* Clear signal flags as the thread is ready now */
158 key = irq_lock();
159 thread_def->signal_results &= signals ? ~(signals) : 0;
160 irq_unlock(key);
161
162 return evt;
163 }
164