blob: 6fb0046f0fef8938504372268e50eb3cd4c21d06 [file] [log] [blame]
/*
* Copyright (c) 2025 Embeint Holdings Pty Ltd
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/modem/at/user_pipe.h>
#include <zephyr/modem/pipelink.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/logging/log.h>
#define AT_UTIL_MODEM_NODE DT_ALIAS(modem)
#define AT_UTIL_PIPELINK_NAME _CONCAT(user_pipe_, CONFIG_MODEM_AT_USER_PIPE_IDX)
#define AT_UTIL_STATE_ATTACHED_BIT 0
#define AT_UTIL_STATE_SCRIPT_RUNNING_BIT 1
MODEM_PIPELINK_DT_DECLARE(AT_UTIL_MODEM_NODE, AT_UTIL_PIPELINK_NAME);
static struct modem_pipelink *at_util_pipelink =
MODEM_PIPELINK_DT_GET(AT_UTIL_MODEM_NODE, AT_UTIL_PIPELINK_NAME);
static struct k_work at_util_open_pipe_work;
static struct k_work at_util_attach_chat_work;
static struct k_work at_util_release_chat_work;
static struct modem_chat *at_util_chat;
static atomic_t at_util_state;
LOG_MODULE_REGISTER(modem_at_user_pipe, CONFIG_MODEM_LOG_LEVEL);
static void at_util_pipe_callback(struct modem_pipe *pipe, enum modem_pipe_event event,
void *user_data)
{
ARG_UNUSED(user_data);
switch (event) {
case MODEM_PIPE_EVENT_OPENED:
LOG_INF("pipe opened");
k_work_submit(&at_util_attach_chat_work);
break;
default:
break;
}
}
void at_util_pipelink_callback(struct modem_pipelink *link, enum modem_pipelink_event event,
void *user_data)
{
ARG_UNUSED(user_data);
switch (event) {
case MODEM_PIPELINK_EVENT_CONNECTED:
LOG_INF("pipe connected");
k_work_submit(&at_util_open_pipe_work);
break;
case MODEM_PIPELINK_EVENT_DISCONNECTED:
LOG_INF("pipe disconnected");
k_work_submit(&at_util_release_chat_work);
break;
default:
break;
}
}
static void at_util_open_pipe_handler(struct k_work *work)
{
ARG_UNUSED(work);
LOG_INF("opening pipe");
modem_pipe_attach(modem_pipelink_get_pipe(at_util_pipelink), at_util_pipe_callback, NULL);
modem_pipe_open_async(modem_pipelink_get_pipe(at_util_pipelink));
}
static void at_util_attach_chat_handler(struct k_work *work)
{
ARG_UNUSED(work);
modem_chat_attach(at_util_chat, modem_pipelink_get_pipe(at_util_pipelink));
atomic_set_bit(&at_util_state, AT_UTIL_STATE_ATTACHED_BIT);
LOG_INF("chat attached");
}
static void at_util_release_chat_handler(struct k_work *work)
{
ARG_UNUSED(work);
modem_chat_release(at_util_chat);
atomic_clear_bit(&at_util_state, AT_UTIL_STATE_ATTACHED_BIT);
LOG_INF("chat released");
}
void modem_at_user_pipe_init(struct modem_chat *chat)
{
at_util_chat = chat;
/* Initialise workers and setup callbacks */
k_work_init(&at_util_open_pipe_work, at_util_open_pipe_handler);
k_work_init(&at_util_attach_chat_work, at_util_attach_chat_handler);
k_work_init(&at_util_release_chat_work, at_util_release_chat_handler);
modem_pipelink_attach(at_util_pipelink, at_util_pipelink_callback, NULL);
}
int modem_at_user_pipe_claim(void)
{
if (!atomic_test_bit(&at_util_state, AT_UTIL_STATE_ATTACHED_BIT)) {
return -EPERM;
}
if (atomic_test_and_set_bit(&at_util_state, AT_UTIL_STATE_SCRIPT_RUNNING_BIT)) {
return -EBUSY;
}
return 0;
}
void modem_at_user_pipe_release(void)
{
atomic_clear_bit(&at_util_state, AT_UTIL_STATE_SCRIPT_RUNNING_BIT);
}