Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/src/sm_cmux.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#endif
#include "sm_util.h"
#include "sm_uart_handler.h"
#include "sm_trace_backend_cmux.h"
#include <zephyr/logging/log.h>
#include <zephyr/modem/cmux.h>
#include <zephyr/modem/pipe.h>
Expand Down Expand Up @@ -339,6 +340,9 @@ static void stop_work_fn(struct k_work *work)

/* Will stop the UART when calling the close_pipe() function. */
if (sm_cmux_is_started()) {
#if defined(CONFIG_SM_MODEM_TRACE_BACKEND_CMUX)
sm_trace_backend_detach();
#endif
modem_cmux_release(&cmux.instance);

close_pipe(&cmux.uart_pipe);
Expand Down Expand Up @@ -437,6 +441,10 @@ static int cmux_start(void)
return ret;
}

#if defined(CONFIG_SM_MODEM_TRACE_BACKEND_CMUX)
sm_trace_backend_attach(sm_cmux_reserve(CMUX_MODEM_TRACE_CHANNEL));
#endif

ret = modem_pipe_open(cmux.uart_pipe, K_SECONDS(CONFIG_SM_MODEM_PIPE_TIMEOUT));
if (!ret) {
cmux.uart_pipe_open = true;
Expand Down
80 changes: 48 additions & 32 deletions app/src/sm_trace_backend_cmux.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
#include <zephyr/modem/pipe.h>
#include <modem/nrf_modem_lib_trace.h>
#include <modem/trace_backend.h>
#include "sm_cmux.h"
#include "sm_util.h"

LOG_MODULE_REGISTER(modem_trace_backend, CONFIG_MODEM_TRACE_BACKEND_LOG_LEVEL);

static K_SEM_DEFINE(tx_idle_sem, 0, 1);

static trace_backend_processed_cb trace_processed_callback;
static struct modem_pipe *trace_pipe;

static void modem_pipe_event_handler(struct modem_pipe *pipe,
enum modem_pipe_event event, void *user_data)
Expand All @@ -25,7 +26,14 @@ static void modem_pipe_event_handler(struct modem_pipe *pipe,
case MODEM_PIPE_EVENT_TRANSMIT_IDLE:
k_sem_give(&tx_idle_sem);
break;

case MODEM_PIPE_EVENT_CLOSED:
LOG_INF("Trace pipe closed");
trace_pipe = NULL;
break;
case MODEM_PIPE_EVENT_OPENED:
LOG_INF("Trace pipe opened");
trace_pipe = pipe;
break;
default:
break;
}
Expand All @@ -38,58 +46,66 @@ int trace_backend_init(trace_backend_processed_cb trace_processed_cb)
}

trace_processed_callback = trace_processed_cb;
trace_pipe = NULL;

return 0;
}

int trace_backend_deinit(void)
{
sm_cmux_release(CMUX_MODEM_TRACE_CHANNEL);

if (trace_pipe) {
modem_pipe_release(trace_pipe);
trace_pipe = NULL;
}
return 0;
}

void sm_trace_backend_attach(struct modem_pipe *pipe)
{
modem_pipe_attach(pipe, modem_pipe_event_handler, NULL);
}

void sm_trace_backend_detach(void)
{
if (trace_pipe) {
modem_pipe_release(trace_pipe);
trace_pipe = NULL;
}
}

int trace_backend_write(const void *data, size_t len)
{
struct modem_pipe *pipe = sm_cmux_reserve(CMUX_MODEM_TRACE_CHANNEL);
const uint8_t *buf = (const uint8_t *)data;
size_t sent_len = 0;
int ret = 0;

if (!sm_cmux_dlci_is_open(CMUX_MODEM_TRACE_CHANNEL)) {
LOG_DBG("Dropped %u bytes.", len);
if (!trace_pipe || !sm_pipe_is_open(trace_pipe)) {
LOG_DBG_RATELIMIT("Pipe closed, dropped %u bytes.", len);
trace_processed_callback(len);
return len;
}

modem_pipe_attach(pipe, modem_pipe_event_handler, NULL);

while (sent_len < len) {
ret = modem_pipe_transmit(pipe, buf, len - sent_len);
if (ret < 0) {
LOG_WRN("TX error (%d). Dropped %u bytes.", ret, len - sent_len);
trace_processed_callback(len);
return ret;
} else if (ret == 0) {
if (k_sem_take(&tx_idle_sem, K_SECONDS(1)) != 0) {
LOG_WRN("TX timeout.");
break;
}
} else {
sent_len += ret;
buf += ret;
}
}
/* No need to retry here.
* The nrf_modem_lib_trace.c:trace_fragment_write() handles
* retrying if the backend returns -EAGAIN.
*
* In congested situations, the modem trace fifos will overflow and drop data.
*/

if (sent_len) {
trace_processed_callback(sent_len);
if (k_sem_take(&tx_idle_sem, K_MSEC(100)) != 0) {
LOG_WRN_RATELIMIT("TX timeout.");
return -EAGAIN;
}

if (sent_len < len) {
LOG_DBG("Sent %u out of %u bytes.", sent_len, len);
ret = modem_pipe_transmit(trace_pipe, data, len);
if (ret < 0) {
LOG_WRN("TX error (%d). Dropped %u bytes.", ret, len);
trace_processed_callback(len);
return ret;
} else if (ret == 0) {
return -EAGAIN;
}
trace_processed_callback(ret);

return sent_len;
return ret;
}

struct nrf_modem_lib_trace_backend trace_backend = {
Expand Down
9 changes: 9 additions & 0 deletions app/src/sm_trace_backend_cmux.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright (c) 2026 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

void sm_trace_backend_attach(struct modem_pipe *pipe);

void sm_trace_backend_detach(void);
2 changes: 1 addition & 1 deletion app/src/sm_uart_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,10 +342,10 @@ static void uart_callback(const struct device *dev, struct uart_event *evt, void
!atomic_test_bit(&uart_state, SM_UART_STATE_TX_ENABLED_BIT))) {
/* TX buffer is empty or we aborted due to TX being disabled. */
k_sem_give(&tx_done_sem);
uart_callback_notify_pipe_transmit_idle();
} else {
tx_start();
}
uart_callback_notify_pipe_transmit_idle();
break;
case UART_RX_RDY:
rx_buf_ref(evt->data.rx.buf);
Expand Down
17 changes: 17 additions & 0 deletions app/src/sm_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <zephyr/net/socket.h>
#include <stdbool.h>
#include <hal/nrf_gpio.h>
#include <zephyr/modem/pipe.h>

extern struct k_work_q sm_work_q; /* Serial Modem's work queue. */

Expand Down Expand Up @@ -206,6 +207,22 @@ struct sm_pdn_dynamic_info {
* @return Zero on success or an error code on failure.
*/
int sm_util_pdn_dynamic_info_get(uint8_t cid, struct sm_pdn_dynamic_info *pdn_info);

#define Z_MODEM_PIPE_EVENT_OPENED_BIT BIT(0)

/**
* @brief Check whether a modem pipe is open
*
* @param pipe Modem pipe to check.
* @return true if pipe is open
* @return false if pipe is not open
*/
static inline bool sm_pipe_is_open(struct modem_pipe *pipe)
{
return k_event_test(&pipe->event, Z_MODEM_PIPE_EVENT_OPENED_BIT) ==
Z_MODEM_PIPE_EVENT_OPENED_BIT;
}

/** @} */

#endif /* SM_UTIL_ */