|  | /* | 
|  | * Copyright (c) 2022 Trackunit Corporation | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #include <zephyr/modem/pipe.h> | 
|  |  | 
|  | #define PIPE_EVENT_OPENED_BIT        BIT(0) | 
|  | #define PIPE_EVENT_CLOSED_BIT        BIT(1) | 
|  | #define PIPE_EVENT_RECEIVE_READY_BIT BIT(2) | 
|  | #define PIPE_EVENT_TRANSMIT_IDLE_BIT BIT(3) | 
|  |  | 
|  | static void pipe_set_callback(struct modem_pipe *pipe, | 
|  | modem_pipe_api_callback callback, | 
|  | void *user_data) | 
|  | { | 
|  | K_SPINLOCK(&pipe->spinlock) { | 
|  | pipe->callback = callback; | 
|  | pipe->user_data = user_data; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void pipe_call_callback(struct modem_pipe *pipe, enum modem_pipe_event event) | 
|  | { | 
|  | K_SPINLOCK(&pipe->spinlock) { | 
|  | if (pipe->callback != NULL) { | 
|  | pipe->callback(pipe, event, pipe->user_data); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static uint32_t pipe_test_events(struct modem_pipe *pipe, uint32_t events) | 
|  | { | 
|  | return k_event_test(&pipe->event, events); | 
|  | } | 
|  |  | 
|  | static uint32_t pipe_await_events(struct modem_pipe *pipe, | 
|  | uint32_t events, | 
|  | k_timeout_t timeout) | 
|  | { | 
|  | return k_event_wait(&pipe->event, events, false, timeout); | 
|  | } | 
|  |  | 
|  | static void pipe_post_events(struct modem_pipe *pipe, uint32_t events) | 
|  | { | 
|  | k_event_post(&pipe->event, events); | 
|  | } | 
|  |  | 
|  | static void pipe_clear_events(struct modem_pipe *pipe, uint32_t events) | 
|  | { | 
|  | k_event_clear(&pipe->event, events); | 
|  | } | 
|  |  | 
|  | static void pipe_set_events(struct modem_pipe *pipe, uint32_t events) | 
|  | { | 
|  | k_event_set(&pipe->event, events); | 
|  | } | 
|  |  | 
|  | static int pipe_call_open(struct modem_pipe *pipe) | 
|  | { | 
|  | return pipe->api->open(pipe->data); | 
|  | } | 
|  |  | 
|  | static int pipe_call_transmit(struct modem_pipe *pipe, const uint8_t *buf, size_t size) | 
|  | { | 
|  | return pipe->api->transmit(pipe->data, buf, size); | 
|  | } | 
|  |  | 
|  | static int pipe_call_receive(struct modem_pipe *pipe, uint8_t *buf, size_t size) | 
|  | { | 
|  | return pipe->api->receive(pipe->data, buf, size); | 
|  | } | 
|  |  | 
|  | static int pipe_call_close(struct modem_pipe *pipe) | 
|  | { | 
|  | return pipe->api->close(pipe->data); | 
|  | } | 
|  |  | 
|  | void modem_pipe_init(struct modem_pipe *pipe, void *data, const struct modem_pipe_api *api) | 
|  | { | 
|  | __ASSERT_NO_MSG(pipe != NULL); | 
|  | __ASSERT_NO_MSG(data != NULL); | 
|  | __ASSERT_NO_MSG(api != NULL); | 
|  |  | 
|  | pipe->data = data; | 
|  | pipe->api = api; | 
|  | pipe->callback = NULL; | 
|  | pipe->user_data = NULL; | 
|  | k_event_init(&pipe->event); | 
|  | } | 
|  |  | 
|  | int modem_pipe_open(struct modem_pipe *pipe, k_timeout_t timeout) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | if (pipe_test_events(pipe, PIPE_EVENT_OPENED_BIT)) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | ret = pipe_call_open(pipe); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | if (!pipe_await_events(pipe, PIPE_EVENT_OPENED_BIT, timeout)) { | 
|  | return -EAGAIN; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int modem_pipe_open_async(struct modem_pipe *pipe) | 
|  | { | 
|  | if (pipe_test_events(pipe, PIPE_EVENT_OPENED_BIT)) { | 
|  | pipe_call_callback(pipe, MODEM_PIPE_EVENT_OPENED); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return pipe_call_open(pipe); | 
|  | } | 
|  |  | 
|  | void modem_pipe_attach(struct modem_pipe *pipe, modem_pipe_api_callback callback, void *user_data) | 
|  | { | 
|  | pipe_set_callback(pipe, callback, user_data); | 
|  |  | 
|  | if (pipe_test_events(pipe, PIPE_EVENT_RECEIVE_READY_BIT)) { | 
|  | pipe_call_callback(pipe, MODEM_PIPE_EVENT_RECEIVE_READY); | 
|  | } | 
|  |  | 
|  | if (pipe_test_events(pipe, PIPE_EVENT_TRANSMIT_IDLE_BIT)) { | 
|  | pipe_call_callback(pipe, MODEM_PIPE_EVENT_TRANSMIT_IDLE); | 
|  | } | 
|  | } | 
|  |  | 
|  | int modem_pipe_transmit(struct modem_pipe *pipe, const uint8_t *buf, size_t size) | 
|  | { | 
|  | if (!pipe_test_events(pipe, PIPE_EVENT_OPENED_BIT)) { | 
|  | return -EPERM; | 
|  | } | 
|  |  | 
|  | pipe_clear_events(pipe, PIPE_EVENT_TRANSMIT_IDLE_BIT); | 
|  | return pipe_call_transmit(pipe, buf, size); | 
|  | } | 
|  |  | 
|  | int modem_pipe_receive(struct modem_pipe *pipe, uint8_t *buf, size_t size) | 
|  | { | 
|  | if (!pipe_test_events(pipe, PIPE_EVENT_OPENED_BIT)) { | 
|  | return -EPERM; | 
|  | } | 
|  |  | 
|  | pipe_clear_events(pipe, PIPE_EVENT_RECEIVE_READY_BIT); | 
|  | return pipe_call_receive(pipe, buf, size); | 
|  | } | 
|  |  | 
|  | void modem_pipe_release(struct modem_pipe *pipe) | 
|  | { | 
|  | pipe_set_callback(pipe, NULL, NULL); | 
|  | } | 
|  |  | 
|  | int modem_pipe_close(struct modem_pipe *pipe, k_timeout_t timeout) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | if (pipe_test_events(pipe, PIPE_EVENT_CLOSED_BIT)) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | ret = pipe_call_close(pipe); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | if (!pipe_await_events(pipe, PIPE_EVENT_CLOSED_BIT, timeout)) { | 
|  | return -EAGAIN; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int modem_pipe_close_async(struct modem_pipe *pipe) | 
|  | { | 
|  | if (pipe_test_events(pipe, PIPE_EVENT_CLOSED_BIT)) { | 
|  | pipe_call_callback(pipe, MODEM_PIPE_EVENT_CLOSED); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return pipe_call_close(pipe); | 
|  | } | 
|  |  | 
|  | void modem_pipe_notify_opened(struct modem_pipe *pipe) | 
|  | { | 
|  | pipe_set_events(pipe, PIPE_EVENT_OPENED_BIT | PIPE_EVENT_TRANSMIT_IDLE_BIT); | 
|  | pipe_call_callback(pipe, MODEM_PIPE_EVENT_OPENED); | 
|  | pipe_call_callback(pipe, MODEM_PIPE_EVENT_TRANSMIT_IDLE); | 
|  | } | 
|  |  | 
|  | void modem_pipe_notify_closed(struct modem_pipe *pipe) | 
|  | { | 
|  | pipe_set_events(pipe, PIPE_EVENT_TRANSMIT_IDLE_BIT | PIPE_EVENT_CLOSED_BIT); | 
|  | pipe_call_callback(pipe, MODEM_PIPE_EVENT_CLOSED); | 
|  | } | 
|  |  | 
|  | void modem_pipe_notify_receive_ready(struct modem_pipe *pipe) | 
|  | { | 
|  | pipe_post_events(pipe, PIPE_EVENT_RECEIVE_READY_BIT); | 
|  | pipe_call_callback(pipe, MODEM_PIPE_EVENT_RECEIVE_READY); | 
|  | } | 
|  |  | 
|  | void modem_pipe_notify_transmit_idle(struct modem_pipe *pipe) | 
|  | { | 
|  | pipe_post_events(pipe, PIPE_EVENT_TRANSMIT_IDLE_BIT); | 
|  | pipe_call_callback(pipe, MODEM_PIPE_EVENT_TRANSMIT_IDLE); | 
|  | } |