1 /*
2  * Copyright (c) 2022 Trackunit Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/types.h>
8 #include <zephyr/kernel.h>
9 
10 #ifndef ZEPHYR_MODEM_PIPE_
11 #define ZEPHYR_MODEM_PIPE_
12 
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16 
17 /**
18  * @brief Modem Pipe
19  * @defgroup modem_pipe Modem Pipe
20  * @ingroup modem
21  * @{
22  */
23 
24 /** Modem pipe event */
25 enum modem_pipe_event {
26 	MODEM_PIPE_EVENT_OPENED = 0,
27 	MODEM_PIPE_EVENT_RECEIVE_READY,
28 	MODEM_PIPE_EVENT_TRANSMIT_IDLE,
29 	MODEM_PIPE_EVENT_CLOSED,
30 };
31 
32 /**
33  * @cond INTERNAL_HIDDEN
34  */
35 
36 struct modem_pipe;
37 
38 /**
39  * @endcond
40  */
41 
42 typedef void (*modem_pipe_api_callback)(struct modem_pipe *pipe, enum modem_pipe_event event,
43 					void *user_data);
44 
45 /**
46  * @cond INTERNAL_HIDDEN
47  */
48 
49 typedef int (*modem_pipe_api_open)(void *data);
50 
51 typedef int (*modem_pipe_api_transmit)(void *data, const uint8_t *buf, size_t size);
52 
53 typedef int (*modem_pipe_api_receive)(void *data, uint8_t *buf, size_t size);
54 
55 typedef int (*modem_pipe_api_close)(void *data);
56 
57 struct modem_pipe_api {
58 	modem_pipe_api_open open;
59 	modem_pipe_api_transmit transmit;
60 	modem_pipe_api_receive receive;
61 	modem_pipe_api_close close;
62 };
63 
64 struct modem_pipe {
65 	void *data;
66 	const struct modem_pipe_api *api;
67 	modem_pipe_api_callback callback;
68 	void *user_data;
69 	struct k_spinlock spinlock;
70 	struct k_event event;
71 };
72 
73 /**
74  * @brief Initialize a modem pipe
75  *
76  * @param pipe Pipe instance to initialize
77  * @param data Pipe data to bind to pipe instance
78  * @param api Pipe API implementation to bind to pipe instance
79  */
80 void modem_pipe_init(struct modem_pipe *pipe, void *data, const struct modem_pipe_api *api);
81 
82 /**
83  * @endcond
84  */
85 
86 /**
87  * @brief Open pipe
88  *
89  * @param pipe Pipe instance
90  * @param timeout Timeout waiting for pipe to open
91  *
92  * @retval 0 if pipe was successfully opened or was already open
93  * @retval -errno code otherwise
94  *
95  * @warning Be cautious when using this synchronous version of the call.
96  * It may block the calling thread, which in the case of the system workqueue
97  * can result in a deadlock until this call times out waiting for the pipe to be open.
98  */
99 int modem_pipe_open(struct modem_pipe *pipe, k_timeout_t timeout);
100 
101 /**
102  * @brief Open pipe asynchronously
103  *
104  * @param pipe Pipe instance
105  *
106  * @note The MODEM_PIPE_EVENT_OPENED event is invoked immediately if pipe is
107  * already opened.
108  *
109  * @retval 0 if pipe open was called successfully or pipe was already open
110  * @retval -errno code otherwise
111  */
112 int modem_pipe_open_async(struct modem_pipe *pipe);
113 
114 /**
115  * @brief Attach pipe to callback
116  *
117  * @param pipe Pipe instance
118  * @param callback Callback called when pipe event occurs
119  * @param user_data Free to use user data passed with callback
120  *
121  * @note The MODEM_PIPE_EVENT_RECEIVE_READY event is invoked immediately if pipe has pending
122  * data ready to receive.
123  */
124 void modem_pipe_attach(struct modem_pipe *pipe, modem_pipe_api_callback callback, void *user_data);
125 
126 /**
127  * @brief Transmit data through pipe
128  *
129  * @param pipe Pipe to transmit through
130  * @param buf Data to transmit
131  * @param size Number of bytes to transmit
132  *
133  * @retval Number of bytes placed in pipe
134  * @retval -EPERM if pipe is closed
135  * @retval -errno code on error
136  *
137  * @warning This call must be non-blocking
138  */
139 int modem_pipe_transmit(struct modem_pipe *pipe, const uint8_t *buf, size_t size);
140 
141 /**
142  * @brief Receive data through pipe
143  *
144  * @param pipe Pipe to receive from
145  * @param buf Destination for received data; must not be already in use in a modem module.
146  * @param size Capacity of destination for received data
147  *
148  * @retval Number of bytes received from pipe
149  * @retval -EPERM if pipe is closed
150  * @retval -errno code on error
151  *
152  * @warning This call must be non-blocking
153  */
154 int modem_pipe_receive(struct modem_pipe *pipe, uint8_t *buf, size_t size);
155 
156 /**
157  * @brief Clear callback
158  *
159  * @param pipe Pipe instance
160  */
161 void modem_pipe_release(struct modem_pipe *pipe);
162 
163 /**
164  * @brief Close pipe
165  *
166  * @param pipe Pipe instance
167  * @param timeout Timeout waiting for pipe to close
168  *
169  * @retval 0 if pipe open was called closed or pipe was already closed
170  * @retval -errno code otherwise
171  *
172  * @warning Be cautious when using this synchronous version of the call.
173  * It may block the calling thread, which in the case of the system workqueue
174  * can result in a deadlock until this call times out waiting for the pipe to be closed.
175  */
176 int modem_pipe_close(struct modem_pipe *pipe, k_timeout_t timeout);
177 
178 /**
179  * @brief Close pipe asynchronously
180  *
181  * @param pipe Pipe instance
182  *
183  * @note The MODEM_PIPE_EVENT_CLOSED event is invoked immediately if pipe is
184  * already closed.
185  *
186  * @retval 0 if pipe close was called successfully or pipe was already closed
187  * @retval -errno code otherwise
188  */
189 int modem_pipe_close_async(struct modem_pipe *pipe);
190 
191 /**
192  * @cond INTERNAL_HIDDEN
193  */
194 
195 /**
196  * @brief Notify user of pipe that it has opened
197  *
198  * @param pipe Pipe instance
199  *
200  * @note Invoked from instance which initialized the pipe instance
201  */
202 void modem_pipe_notify_opened(struct modem_pipe *pipe);
203 
204 /**
205  * @brief Notify user of pipe that it has closed
206  *
207  * @param pipe Pipe instance
208  *
209  * @note Invoked from instance which initialized the pipe instance
210  */
211 void modem_pipe_notify_closed(struct modem_pipe *pipe);
212 
213 /**
214  * @brief Notify user of pipe that data is ready to be received
215  *
216  * @param pipe Pipe instance
217  *
218  * @note Invoked from instance which initialized the pipe instance
219  */
220 void modem_pipe_notify_receive_ready(struct modem_pipe *pipe);
221 
222 /**
223  * @brief Notify user of pipe that pipe has no more data to transmit
224  *
225  * @param pipe Pipe instance
226  *
227  * @note Invoked from instance which initialized the pipe instance
228  */
229 void modem_pipe_notify_transmit_idle(struct modem_pipe *pipe);
230 
231 /**
232  * @endcond
233  */
234 
235 /**
236  * @}
237  */
238 
239 #ifdef __cplusplus
240 }
241 #endif
242 
243 #endif /* ZEPHYR_MODEM_PIPE_ */
244