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