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