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