1 /*
2  * Copyright (c) 2022 Trackunit Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/modem/pipe.h>
8 
9 #define PIPE_EVENT_OPENED_BIT        BIT(0)
10 #define PIPE_EVENT_CLOSED_BIT        BIT(1)
11 #define PIPE_EVENT_RECEIVE_READY_BIT BIT(2)
12 #define PIPE_EVENT_TRANSMIT_IDLE_BIT BIT(3)
13 
pipe_set_callback(struct modem_pipe * pipe,modem_pipe_api_callback callback,void * user_data)14 static void pipe_set_callback(struct modem_pipe *pipe,
15 			      modem_pipe_api_callback callback,
16 			      void *user_data)
17 {
18 	K_SPINLOCK(&pipe->spinlock) {
19 		pipe->callback = callback;
20 		pipe->user_data = user_data;
21 	}
22 }
23 
pipe_call_callback(struct modem_pipe * pipe,enum modem_pipe_event event)24 static void pipe_call_callback(struct modem_pipe *pipe, enum modem_pipe_event event)
25 {
26 	K_SPINLOCK(&pipe->spinlock) {
27 		if (pipe->callback != NULL) {
28 			pipe->callback(pipe, event, pipe->user_data);
29 		}
30 	}
31 }
32 
pipe_test_events(struct modem_pipe * pipe,uint32_t events)33 static uint32_t pipe_test_events(struct modem_pipe *pipe, uint32_t events)
34 {
35 	return k_event_test(&pipe->event, events);
36 }
37 
pipe_await_events(struct modem_pipe * pipe,uint32_t events,k_timeout_t timeout)38 static uint32_t pipe_await_events(struct modem_pipe *pipe,
39 				  uint32_t events,
40 				  k_timeout_t timeout)
41 {
42 	return k_event_wait(&pipe->event, events, false, timeout);
43 }
44 
pipe_post_events(struct modem_pipe * pipe,uint32_t events)45 static void pipe_post_events(struct modem_pipe *pipe, uint32_t events)
46 {
47 	k_event_post(&pipe->event, events);
48 }
49 
pipe_clear_events(struct modem_pipe * pipe,uint32_t events)50 static void pipe_clear_events(struct modem_pipe *pipe, uint32_t events)
51 {
52 	k_event_clear(&pipe->event, events);
53 }
54 
pipe_set_events(struct modem_pipe * pipe,uint32_t events)55 static void pipe_set_events(struct modem_pipe *pipe, uint32_t events)
56 {
57 	k_event_set(&pipe->event, events);
58 }
59 
pipe_call_open(struct modem_pipe * pipe)60 static int pipe_call_open(struct modem_pipe *pipe)
61 {
62 	return pipe->api->open(pipe->data);
63 }
64 
pipe_call_transmit(struct modem_pipe * pipe,const uint8_t * buf,size_t size)65 static int pipe_call_transmit(struct modem_pipe *pipe, const uint8_t *buf, size_t size)
66 {
67 	return pipe->api->transmit(pipe->data, buf, size);
68 }
69 
pipe_call_receive(struct modem_pipe * pipe,uint8_t * buf,size_t size)70 static int pipe_call_receive(struct modem_pipe *pipe, uint8_t *buf, size_t size)
71 {
72 	return pipe->api->receive(pipe->data, buf, size);
73 }
74 
pipe_call_close(struct modem_pipe * pipe)75 static int pipe_call_close(struct modem_pipe *pipe)
76 {
77 	return pipe->api->close(pipe->data);
78 }
79 
modem_pipe_init(struct modem_pipe * pipe,void * data,const struct modem_pipe_api * api)80 void modem_pipe_init(struct modem_pipe *pipe, void *data, const struct modem_pipe_api *api)
81 {
82 	__ASSERT_NO_MSG(pipe != NULL);
83 	__ASSERT_NO_MSG(data != NULL);
84 	__ASSERT_NO_MSG(api != NULL);
85 
86 	pipe->data = data;
87 	pipe->api = api;
88 	pipe->callback = NULL;
89 	pipe->user_data = NULL;
90 	k_event_init(&pipe->event);
91 }
92 
modem_pipe_open(struct modem_pipe * pipe,k_timeout_t timeout)93 int modem_pipe_open(struct modem_pipe *pipe, k_timeout_t timeout)
94 {
95 	int ret;
96 
97 	if (pipe_test_events(pipe, PIPE_EVENT_OPENED_BIT)) {
98 		return 0;
99 	}
100 
101 	ret = pipe_call_open(pipe);
102 	if (ret < 0) {
103 		return ret;
104 	}
105 
106 	if (!pipe_await_events(pipe, PIPE_EVENT_OPENED_BIT, timeout)) {
107 		return -EAGAIN;
108 	}
109 
110 	return 0;
111 }
112 
modem_pipe_open_async(struct modem_pipe * pipe)113 int modem_pipe_open_async(struct modem_pipe *pipe)
114 {
115 	if (pipe_test_events(pipe, PIPE_EVENT_OPENED_BIT)) {
116 		pipe_call_callback(pipe, MODEM_PIPE_EVENT_OPENED);
117 		return 0;
118 	}
119 
120 	return pipe_call_open(pipe);
121 }
122 
modem_pipe_attach(struct modem_pipe * pipe,modem_pipe_api_callback callback,void * user_data)123 void modem_pipe_attach(struct modem_pipe *pipe, modem_pipe_api_callback callback, void *user_data)
124 {
125 	pipe_set_callback(pipe, callback, user_data);
126 
127 	if (pipe_test_events(pipe, PIPE_EVENT_RECEIVE_READY_BIT)) {
128 		pipe_call_callback(pipe, MODEM_PIPE_EVENT_RECEIVE_READY);
129 	}
130 
131 	if (pipe_test_events(pipe, PIPE_EVENT_TRANSMIT_IDLE_BIT)) {
132 		pipe_call_callback(pipe, MODEM_PIPE_EVENT_TRANSMIT_IDLE);
133 	}
134 }
135 
modem_pipe_transmit(struct modem_pipe * pipe,const uint8_t * buf,size_t size)136 int modem_pipe_transmit(struct modem_pipe *pipe, const uint8_t *buf, size_t size)
137 {
138 	if (!pipe_test_events(pipe, PIPE_EVENT_OPENED_BIT)) {
139 		return -EPERM;
140 	}
141 
142 	pipe_clear_events(pipe, PIPE_EVENT_TRANSMIT_IDLE_BIT);
143 	return pipe_call_transmit(pipe, buf, size);
144 }
145 
modem_pipe_receive(struct modem_pipe * pipe,uint8_t * buf,size_t size)146 int modem_pipe_receive(struct modem_pipe *pipe, uint8_t *buf, size_t size)
147 {
148 	if (!pipe_test_events(pipe, PIPE_EVENT_OPENED_BIT)) {
149 		return -EPERM;
150 	}
151 
152 	pipe_clear_events(pipe, PIPE_EVENT_RECEIVE_READY_BIT);
153 	return pipe_call_receive(pipe, buf, size);
154 }
155 
modem_pipe_release(struct modem_pipe * pipe)156 void modem_pipe_release(struct modem_pipe *pipe)
157 {
158 	pipe_set_callback(pipe, NULL, NULL);
159 }
160 
modem_pipe_close(struct modem_pipe * pipe,k_timeout_t timeout)161 int modem_pipe_close(struct modem_pipe *pipe, k_timeout_t timeout)
162 {
163 	int ret;
164 
165 	if (pipe_test_events(pipe, PIPE_EVENT_CLOSED_BIT)) {
166 		return 0;
167 	}
168 
169 	ret = pipe_call_close(pipe);
170 	if (ret < 0) {
171 		return ret;
172 	}
173 
174 	if (!pipe_await_events(pipe, PIPE_EVENT_CLOSED_BIT, timeout)) {
175 		return -EAGAIN;
176 	}
177 
178 	return 0;
179 }
180 
modem_pipe_close_async(struct modem_pipe * pipe)181 int modem_pipe_close_async(struct modem_pipe *pipe)
182 {
183 	if (pipe_test_events(pipe, PIPE_EVENT_CLOSED_BIT)) {
184 		pipe_call_callback(pipe, MODEM_PIPE_EVENT_CLOSED);
185 		return 0;
186 	}
187 
188 	return pipe_call_close(pipe);
189 }
190 
modem_pipe_notify_opened(struct modem_pipe * pipe)191 void modem_pipe_notify_opened(struct modem_pipe *pipe)
192 {
193 	pipe_set_events(pipe, PIPE_EVENT_OPENED_BIT | PIPE_EVENT_TRANSMIT_IDLE_BIT);
194 	pipe_call_callback(pipe, MODEM_PIPE_EVENT_OPENED);
195 	pipe_call_callback(pipe, MODEM_PIPE_EVENT_TRANSMIT_IDLE);
196 }
197 
modem_pipe_notify_closed(struct modem_pipe * pipe)198 void modem_pipe_notify_closed(struct modem_pipe *pipe)
199 {
200 	pipe_set_events(pipe, PIPE_EVENT_TRANSMIT_IDLE_BIT | PIPE_EVENT_CLOSED_BIT);
201 	pipe_call_callback(pipe, MODEM_PIPE_EVENT_CLOSED);
202 }
203 
modem_pipe_notify_receive_ready(struct modem_pipe * pipe)204 void modem_pipe_notify_receive_ready(struct modem_pipe *pipe)
205 {
206 	pipe_post_events(pipe, PIPE_EVENT_RECEIVE_READY_BIT);
207 	pipe_call_callback(pipe, MODEM_PIPE_EVENT_RECEIVE_READY);
208 }
209 
modem_pipe_notify_transmit_idle(struct modem_pipe * pipe)210 void modem_pipe_notify_transmit_idle(struct modem_pipe *pipe)
211 {
212 	pipe_post_events(pipe, PIPE_EVENT_TRANSMIT_IDLE_BIT);
213 	pipe_call_callback(pipe, MODEM_PIPE_EVENT_TRANSMIT_IDLE);
214 }
215