125 lines
3.3 KiB
C
125 lines
3.3 KiB
C
/*
|
|
* Copyright (c) 2022 Trackunit Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/modem/backend/tty.h>
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(modem_backend_tty);
|
|
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <poll.h>
|
|
#include <string.h>
|
|
|
|
#define MODEM_BACKEND_TTY_THREAD_PRIO (10)
|
|
#define MODEM_BACKEND_TTY_THREAD_RUN_PERIOD_MS (1000)
|
|
#define MODEM_BACKEND_TTY_THREAD_POLL_DELAY (100)
|
|
|
|
#define MODEM_BACKEND_TTY_STATE_RUN_BIT (1)
|
|
|
|
static void modem_backend_tty_routine(void *p1, void *p2, void *p3)
|
|
{
|
|
struct modem_backend_tty *backend = (struct modem_backend_tty *)p1;
|
|
struct pollfd pd;
|
|
|
|
ARG_UNUSED(p2);
|
|
ARG_UNUSED(p3);
|
|
|
|
pd.fd = backend->tty_fd;
|
|
pd.events = POLLIN;
|
|
|
|
/* Run until run flag is cleared. Check every MODEM_BACKEND_TTY_THREAD_RUN_PERIOD_MS */
|
|
while (atomic_test_bit(&backend->state, MODEM_BACKEND_TTY_STATE_RUN_BIT)) {
|
|
/* Clear events */
|
|
pd.revents = 0;
|
|
|
|
if (poll(&pd, 1, MODEM_BACKEND_TTY_THREAD_RUN_PERIOD_MS) < 0) {
|
|
LOG_ERR("Poll operation failed");
|
|
break;
|
|
}
|
|
|
|
if (pd.revents & POLLIN) {
|
|
modem_pipe_notify_receive_ready(&backend->pipe);
|
|
}
|
|
|
|
k_sleep(K_MSEC(MODEM_BACKEND_TTY_THREAD_POLL_DELAY));
|
|
}
|
|
}
|
|
|
|
static int modem_backend_tty_open(void *data)
|
|
{
|
|
struct modem_backend_tty *backend = (struct modem_backend_tty *)data;
|
|
|
|
if (atomic_test_and_set_bit(&backend->state, MODEM_BACKEND_TTY_STATE_RUN_BIT)) {
|
|
return -EALREADY;
|
|
}
|
|
|
|
backend->tty_fd = open(backend->tty_path, (O_RDWR | O_NONBLOCK), 0644);
|
|
if (backend->tty_fd < 0) {
|
|
return -EPERM;
|
|
}
|
|
|
|
k_thread_create(&backend->thread, backend->stack, backend->stack_size,
|
|
modem_backend_tty_routine, backend, NULL, NULL,
|
|
MODEM_BACKEND_TTY_THREAD_PRIO, 0, K_NO_WAIT);
|
|
|
|
modem_pipe_notify_opened(&backend->pipe);
|
|
return 0;
|
|
}
|
|
|
|
static int modem_backend_tty_transmit(void *data, const uint8_t *buf, size_t size)
|
|
{
|
|
struct modem_backend_tty *backend = (struct modem_backend_tty *)data;
|
|
|
|
return write(backend->tty_fd, buf, size);
|
|
}
|
|
|
|
static int modem_backend_tty_receive(void *data, uint8_t *buf, size_t size)
|
|
{
|
|
int ret;
|
|
struct modem_backend_tty *backend = (struct modem_backend_tty *)data;
|
|
|
|
ret = read(backend->tty_fd, buf, size);
|
|
return (ret < 0) ? 0 : ret;
|
|
}
|
|
|
|
static int modem_backend_tty_close(void *data)
|
|
{
|
|
struct modem_backend_tty *backend = (struct modem_backend_tty *)data;
|
|
|
|
if (!atomic_test_and_clear_bit(&backend->state, MODEM_BACKEND_TTY_STATE_RUN_BIT)) {
|
|
return -EALREADY;
|
|
}
|
|
|
|
k_thread_join(&backend->thread, K_MSEC(MODEM_BACKEND_TTY_THREAD_RUN_PERIOD_MS * 2));
|
|
close(backend->tty_fd);
|
|
modem_pipe_notify_closed(&backend->pipe);
|
|
return 0;
|
|
}
|
|
|
|
struct modem_pipe_api modem_backend_tty_api = {
|
|
.open = modem_backend_tty_open,
|
|
.transmit = modem_backend_tty_transmit,
|
|
.receive = modem_backend_tty_receive,
|
|
.close = modem_backend_tty_close,
|
|
};
|
|
|
|
struct modem_pipe *modem_backend_tty_init(struct modem_backend_tty *backend,
|
|
const struct modem_backend_tty_config *config)
|
|
{
|
|
__ASSERT_NO_MSG(backend != NULL);
|
|
__ASSERT_NO_MSG(config != NULL);
|
|
__ASSERT_NO_MSG(config->tty_path != NULL);
|
|
|
|
memset(backend, 0x00, sizeof(*backend));
|
|
backend->tty_path = config->tty_path;
|
|
backend->stack = config->stack;
|
|
backend->stack_size = config->stack_size;
|
|
atomic_set(&backend->state, 0);
|
|
modem_pipe_init(&backend->pipe, backend, &modem_backend_tty_api);
|
|
return &backend->pipe;
|
|
}
|