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