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 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(modem_pipe, CONFIG_MODEM_MODULES_LOG_LEVEL);
11 
modem_pipe_init(struct modem_pipe * pipe,void * data,struct modem_pipe_api * api)12 void modem_pipe_init(struct modem_pipe *pipe, void *data, struct modem_pipe_api *api)
13 {
14 	__ASSERT_NO_MSG(pipe != NULL);
15 	__ASSERT_NO_MSG(data != NULL);
16 	__ASSERT_NO_MSG(api != NULL);
17 
18 	pipe->data = data;
19 	pipe->api = api;
20 	pipe->callback = NULL;
21 	pipe->user_data = NULL;
22 	pipe->state = MODEM_PIPE_STATE_CLOSED;
23 	pipe->receive_ready_pending = false;
24 
25 	k_mutex_init(&pipe->lock);
26 	k_condvar_init(&pipe->condvar);
27 }
28 
modem_pipe_open(struct modem_pipe * pipe)29 int modem_pipe_open(struct modem_pipe *pipe)
30 {
31 	int ret;
32 
33 	k_mutex_lock(&pipe->lock, K_FOREVER);
34 	if (pipe->state == MODEM_PIPE_STATE_OPEN) {
35 		k_mutex_unlock(&pipe->lock);
36 		return 0;
37 	}
38 
39 	ret = pipe->api->open(pipe->data);
40 	if (ret < 0) {
41 		k_mutex_unlock(&pipe->lock);
42 		return ret;
43 	}
44 
45 	if (pipe->state == MODEM_PIPE_STATE_OPEN) {
46 		k_mutex_unlock(&pipe->lock);
47 		return 0;
48 	}
49 
50 	k_condvar_wait(&pipe->condvar, &pipe->lock, K_MSEC(10000));
51 	ret = (pipe->state == MODEM_PIPE_STATE_OPEN) ? 0 : -EAGAIN;
52 	k_mutex_unlock(&pipe->lock);
53 	return ret;
54 }
55 
modem_pipe_open_async(struct modem_pipe * pipe)56 int modem_pipe_open_async(struct modem_pipe *pipe)
57 {
58 	int ret;
59 
60 	k_mutex_lock(&pipe->lock, K_FOREVER);
61 	if (pipe->state == MODEM_PIPE_STATE_OPEN) {
62 		if (pipe->callback != NULL) {
63 			pipe->callback(pipe, MODEM_PIPE_EVENT_OPENED, pipe->user_data);
64 		}
65 
66 		k_mutex_unlock(&pipe->lock);
67 		return 0;
68 	}
69 
70 	ret = pipe->api->open(pipe->data);
71 	k_mutex_unlock(&pipe->lock);
72 	return ret;
73 }
74 
modem_pipe_attach(struct modem_pipe * pipe,modem_pipe_api_callback callback,void * user_data)75 void modem_pipe_attach(struct modem_pipe *pipe, modem_pipe_api_callback callback, void *user_data)
76 {
77 	k_mutex_lock(&pipe->lock, K_FOREVER);
78 	pipe->callback = callback;
79 	pipe->user_data = user_data;
80 
81 	if (pipe->receive_ready_pending && (pipe->callback != NULL)) {
82 		pipe->callback(pipe, MODEM_PIPE_EVENT_RECEIVE_READY, pipe->user_data);
83 	}
84 
85 	k_mutex_unlock(&pipe->lock);
86 }
87 
modem_pipe_transmit(struct modem_pipe * pipe,const uint8_t * buf,size_t size)88 int modem_pipe_transmit(struct modem_pipe *pipe, const uint8_t *buf, size_t size)
89 {
90 	int ret;
91 
92 	k_mutex_lock(&pipe->lock, K_FOREVER);
93 
94 	if (pipe->state == MODEM_PIPE_STATE_CLOSED) {
95 		k_mutex_unlock(&pipe->lock);
96 		return -EPERM;
97 	}
98 
99 	ret = pipe->api->transmit(pipe->data, buf, size);
100 	k_mutex_unlock(&pipe->lock);
101 	return ret;
102 }
103 
modem_pipe_receive(struct modem_pipe * pipe,uint8_t * buf,size_t size)104 int modem_pipe_receive(struct modem_pipe *pipe, uint8_t *buf, size_t size)
105 {
106 	int ret;
107 
108 	k_mutex_lock(&pipe->lock, K_FOREVER);
109 
110 	if (pipe->state == MODEM_PIPE_STATE_CLOSED) {
111 		k_mutex_unlock(&pipe->lock);
112 		return -EPERM;
113 	}
114 
115 	ret = pipe->api->receive(pipe->data, buf, size);
116 	pipe->receive_ready_pending = false;
117 	k_mutex_unlock(&pipe->lock);
118 	return ret;
119 }
120 
modem_pipe_release(struct modem_pipe * pipe)121 void modem_pipe_release(struct modem_pipe *pipe)
122 {
123 	k_mutex_lock(&pipe->lock, K_FOREVER);
124 	pipe->callback = NULL;
125 	pipe->user_data = NULL;
126 	k_mutex_unlock(&pipe->lock);
127 }
128 
modem_pipe_close(struct modem_pipe * pipe)129 int modem_pipe_close(struct modem_pipe *pipe)
130 {
131 	int ret;
132 
133 	k_mutex_lock(&pipe->lock, K_FOREVER);
134 	if (pipe->state == MODEM_PIPE_STATE_CLOSED) {
135 		k_mutex_unlock(&pipe->lock);
136 		return 0;
137 	}
138 
139 	ret = pipe->api->close(pipe->data);
140 	if (ret < 0) {
141 		k_mutex_unlock(&pipe->lock);
142 		return ret;
143 	}
144 
145 	if (pipe->state == MODEM_PIPE_STATE_CLOSED) {
146 		k_mutex_unlock(&pipe->lock);
147 		return 0;
148 	}
149 
150 	k_condvar_wait(&pipe->condvar, &pipe->lock, K_MSEC(10000));
151 	ret = (pipe->state == MODEM_PIPE_STATE_CLOSED) ? 0 : -EAGAIN;
152 	k_mutex_unlock(&pipe->lock);
153 	return ret;
154 }
155 
modem_pipe_close_async(struct modem_pipe * pipe)156 int modem_pipe_close_async(struct modem_pipe *pipe)
157 {
158 	int ret;
159 
160 	k_mutex_lock(&pipe->lock, K_FOREVER);
161 	if (pipe->state == MODEM_PIPE_STATE_CLOSED) {
162 		if (pipe->callback != NULL) {
163 			pipe->callback(pipe, MODEM_PIPE_EVENT_CLOSED, pipe->user_data);
164 		}
165 
166 		k_mutex_unlock(&pipe->lock);
167 		return 0;
168 	}
169 
170 	ret = pipe->api->close(pipe->data);
171 	k_mutex_unlock(&pipe->lock);
172 	return ret;
173 }
174 
modem_pipe_notify_opened(struct modem_pipe * pipe)175 void modem_pipe_notify_opened(struct modem_pipe *pipe)
176 {
177 	k_mutex_lock(&pipe->lock, K_FOREVER);
178 	pipe->state = MODEM_PIPE_STATE_OPEN;
179 
180 	if (pipe->callback != NULL) {
181 		pipe->callback(pipe, MODEM_PIPE_EVENT_OPENED, pipe->user_data);
182 	}
183 
184 	k_condvar_signal(&pipe->condvar);
185 	k_mutex_unlock(&pipe->lock);
186 }
187 
modem_pipe_notify_closed(struct modem_pipe * pipe)188 void modem_pipe_notify_closed(struct modem_pipe *pipe)
189 {
190 	k_mutex_lock(&pipe->lock, K_FOREVER);
191 	pipe->state = MODEM_PIPE_STATE_CLOSED;
192 	pipe->receive_ready_pending = false;
193 
194 	if (pipe->callback != NULL) {
195 		pipe->callback(pipe, MODEM_PIPE_EVENT_CLOSED, pipe->user_data);
196 	}
197 
198 	k_condvar_signal(&pipe->condvar);
199 	k_mutex_unlock(&pipe->lock);
200 }
201 
modem_pipe_notify_receive_ready(struct modem_pipe * pipe)202 void modem_pipe_notify_receive_ready(struct modem_pipe *pipe)
203 {
204 	k_mutex_lock(&pipe->lock, K_FOREVER);
205 
206 	pipe->receive_ready_pending = true;
207 
208 	if (pipe->callback != NULL) {
209 		pipe->callback(pipe, MODEM_PIPE_EVENT_RECEIVE_READY, pipe->user_data);
210 	}
211 
212 	k_mutex_unlock(&pipe->lock);
213 }
214