Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

applications: serial_lte_modem: Add Linux PPP+CMUX support #21135

Merged
merged 2 commits into from
Mar 27, 2025
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
17 changes: 15 additions & 2 deletions applications/serial_lte_modem/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,26 @@ config SLM_UART_RX_BUF_COUNT
range 2 4
default 3
help
Amount of buffers for receiving (RX) UART traffic. If the buffers are full, UART RX will be disabled until the buffers are processed.
Amount of buffers for receiving (RX) UART traffic.
If the buffers are full, UART RX will be disabled until the buffers are processed.
These buffers are not used when CMUX is in use.

config SLM_UART_RX_BUF_SIZE
int "Receive buffer size for UART"
range 128 4096
default 256
help
Amount of received (RX), unprocessed, UART traffic that can be held by single buffer.
These buffers are not used when CMUX is in use.

config SLM_UART_TX_BUF_SIZE
int "Send buffer size for UART"
range 128 4096
default 256
help
Amount of UART traffic waiting to be sent (TX), that can be held. If the buffers are full, will send synchronously.
Amount of UART traffic waiting to be sent (TX), that can be held.
If the buffers are full, will send synchronously.
These buffers are not used when CMUX is in use.

#
# GPIO functionality
Expand Down Expand Up @@ -181,6 +186,14 @@ endif
config SLM_CMUX
bool "CMUX support in SLM"

config SLM_CMUX_UART_BUFFER_SIZE
int "UART buffer size for CMUX"
depends on SLM_CMUX
default 6000
help
Size of the buffer for data received in CMUX mode.
Same buffer size is used for both RX and TX.

if SLM_CMUX && SLM_PPP

config SLM_CMUX_AUTOMATIC_FALLBACK_ON_PPP_STOPPAGE
Expand Down
1 change: 1 addition & 0 deletions applications/serial_lte_modem/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ See the subpages for how to use the application, how to extend it, and informati

doc/slm_description
doc/nRF91_as_Zephyr_modem
doc/PPP_linux
doc/slm_testing
doc/slm_extending
doc/slm_data_mode
Expand Down
141 changes: 141 additions & 0 deletions applications/serial_lte_modem/doc/PPP_linux.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
.. _slm_as_linux_modem:

nRF91 Series SiP as a modem for Linux device
############################################

.. contents::
:local:
:depth: 2

Overview
********

You can use the Serial LTE Modem (SLM) application to make an nRF91 Series SiP work as a standalone modem that can be used with a Linux device.
The Linux device can use a standard PPP daemon and ldattach utility to connect to the cellular network through the nRF91 Series SiP.

The setup differentiates from a typical dial-up modem connection as the GSM 0710 multiplexer protocol (CMUX) is used to multiplex multiple data streams over a single serial port.
This allows you to use the same serial port for both AT commands and PPP data.

Prerequisites
=============

The Linux device needs to have the following packages installed:

* pppd from the ppp package
* ldattach from the util-linux package

These should be available on all standard Linux distributions.

Configuration
=============

To build the SLM application, use the :file:`overlay-ppp-cmux-linux.conf` configuration overlay.

You can adjust the serial port baud rate using the devicetree overlay file.
By default, the baud rate is set to 115200.
If you change the baud rate, set the same rate in the :file:`scripts/slm_start_ppp.sh` and :file:`scripts/slm_stop_ppp.sh` scripts.

Building and running
====================

To build and program the SLM application to the nRF91 Series device, use the :file:`overlay-ppp-cmux-linux.conf` overlay file.

Managing the connection
=======================

The start and stop scripts are provided in the :file:`scripts` directory of the SLM application.
The scripts assume that the nRF91 Series SiP is connected to the Linux device using the `/dev/ttyACM0` serial port.

If needed, adjust the serial port settings in the scripts as follows:

.. code-block:: none

MODEM=/dev/ttyACM0
BAUD=115200

To start the PPP connection, run the :file:`scripts/slm_start_ppp.sh` script.
To stop the PPP connection, run the :file:`scripts/slm_stop_ppp.sh` script.

The scripts need superuser privileges to run, so use `sudo`.
The PPP link is set as a default route if there is no existing default route.
The scripts do not manage the DNS settings from the Linux system.
Read the distribution manuals to learn how to configure the DNS settings.

The following example shows how to start the connection and verify its operation with various command-line utilities:

.. code-block:: shell

$ sudo scripts/slm_start_ppp.sh
Wait modem to boot
Attach CMUX channel to modem...
Connect and wait for PPP link...
send (AT+CFUN=1^M)
expect (OK)


OK
-- got it

send ()
expect (#XPPP: 1,0)




#XPPP: 1,0
-- got it

$ ip addr show ppp0
7: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1464 qdisc fq_codel state UNKNOWN group default qlen 3
link/ppp
inet 10.139.130.66/32 scope global ppp0
valid_lft forever preferred_lft forever
inet6 2001:14bb:69b:50a3:ade3:2fce:6cc:ba3c/64 scope global temporary dynamic
valid_lft 604720sec preferred_lft 85857sec
inet6 2001:14bb:69b:50a3:40f9:1c4e:7231:638b/64 scope global dynamic mngtmpaddr
valid_lft forever preferred_lft forever
inet6 fe80::40f9:1c4e:7231:638b peer fe80::3c29:6401/128 scope link
valid_lft forever preferred_lft forever

$ ping -I ppp0 8.8.8.8 -c5
PING 8.8.8.8 (8.8.8.8) from 10.139.130.66 ppp0: 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=60 time=320 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=60 time=97.6 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=60 time=140 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=60 time=132 ms
64 bytes from 8.8.8.8: icmp_seq=5 ttl=60 time=145 ms

--- 8.8.8.8 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4007ms
rtt min/avg/max/mdev = 97.610/166.802/319.778/78.251 ms

$ iperf3 -c ping.online.net%ppp0 -p 5202
Connecting to host ping.online.net, port 5202
[ 5] local 10.139.130.66 port 54244 connected to 51.158.1.21 port 5202
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 0.00 Bytes 0.00 bits/sec 1 17.6 KBytes
[ 5] 1.00-2.00 sec 0.00 Bytes 0.00 bits/sec 0 25.8 KBytes
[ 5] 2.00-3.00 sec 0.00 Bytes 0.00 bits/sec 0 32.5 KBytes
[ 5] 3.00-4.00 sec 128 KBytes 1.05 Mbits/sec 0 35.2 KBytes
[ 5] 4.00-5.00 sec 0.00 Bytes 0.00 bits/sec 0 35.2 KBytes
[ 5] 5.00-6.00 sec 0.00 Bytes 0.00 bits/sec 0 35.2 KBytes
[ 5] 6.00-7.00 sec 0.00 Bytes 0.00 bits/sec 0 35.2 KBytes
[ 5] 7.00-8.00 sec 0.00 Bytes 0.00 bits/sec 0 35.2 KBytes
[ 5] 8.00-9.00 sec 0.00 Bytes 0.00 bits/sec 0 35.2 KBytes
[ 5] 9.00-10.00 sec 0.00 Bytes 0.00 bits/sec 0 35.2 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 128 KBytes 105 Kbits/sec 1 sender
[ 5] 0.00-11.58 sec 89.5 KBytes 63.3 Kbits/sec receiver

$ sudo scripts/slm_stop_ppp.sh
send (AT+CFUN=0^M)
expect (#XPPP: 0,0)


OK



#XPPP: 0,0
-- got it
65 changes: 65 additions & 0 deletions applications/serial_lte_modem/overlay-ppp-cmux-linux.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#
# Copyright (c) 2025 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

CONFIG_SLM_SKIP_READY_MSG=y
CONFIG_SLM_CMUX=y
CONFIG_SLM_PPP=y
CONFIG_SLM_CR_TERMINATION=y

# Assume at least baudrate 115200 for UART
# so CMUX frame can be received in 12 ms (134*10/115200)
CONFIG_MODEM_BACKEND_UART_ASYNC_RECEIVE_IDLE_TIMEOUT_MS=12
CONFIG_MODEM_CMUX_MTU=127
CONFIG_MODEM_CMUX_WORK_BUFFER_SIZE=536
CONFIG_SLM_CMUX_UART_BUFFER_SIZE=6000
# For sending full 6000 bytes at 115200 baudrate
# 6000 * 10 / 115200 = 521 ms
CONFIG_MODEM_BACKEND_UART_ASYNC_TRANSMIT_TIMEOUT_MS=521

# These buffers are unused after AT#CMUX is enabled
# so use minimal buffer size
CONFIG_SLM_UART_RX_BUF_COUNT=3
CONFIG_SLM_UART_RX_BUF_SIZE=128
CONFIG_SLM_UART_TX_BUF_SIZE=128

# When using PPP, disable commands of IP-based protocols to save flash space.
CONFIG_SLM_FTPC=n
CONFIG_SLM_TFTPC=n
CONFIG_SLM_HTTPC=n
CONFIG_SLM_MQTTC=n

# nRF Connect SDK modules
CONFIG_PDN=y
CONFIG_AT_CMD_CUSTOM=y
CONFIG_NRF_MODEM_LIB_SHMEM_TX_SIZE=22528

# Zephyr modules
CONFIG_NET_NATIVE=y
CONFIG_NET_L2_PPP=y
CONFIG_MODEM_MODULES=y
CONFIG_MODEM_CMUX=y
CONFIG_MODEM_PPP=y
CONFIG_MODEM_BACKEND_UART=y

# L2 protocol
CONFIG_NET_L2_PPP_MGMT=y
CONFIG_NET_L2_PPP_OPTION_MRU=y
CONFIG_NET_L2_PPP_OPTION_SERVE_IP=y
CONFIG_NET_L2_PPP_OPTION_SERVE_DNS=y
CONFIG_NET_L2_PPP_TIMEOUT=5000

# IP stack
CONFIG_NET_IP_ADDR_CHECK=n
CONFIG_NET_SOCKETS_PACKET=y

# network buffering
CONFIG_NET_BUF=y
CONFIG_NET_BUF_POOL_USAGE=y
CONFIG_NET_PKT_RX_COUNT=44
CONFIG_NET_BUF_RX_COUNT=88
CONFIG_NET_PKT_TX_COUNT=44
CONFIG_NET_BUF_TX_COUNT=88
CONFIG_NET_TC_RX_COUNT=0
48 changes: 48 additions & 0 deletions applications/serial_lte_modem/scripts/slm_start_ppp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash -eu
#
# Copyright (c) 2025 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause

#
# Script to start PPP link inside CMUX channel
# using Serial LTE Modem
#

MODEM=/dev/ttyACM0
BAUD=115200
PPP_CMUX=/dev/gsmtty2
AT_CMUX=/dev/gsmtty1
CHATOPT="-vs"

cleanup() {
set +eu
pkill pppd
pkill ldattach
echo "Failed to start..."
exit 1
}
trap cleanup ERR

if [[ ! -c $MODEM ]]; then
echo "Serial port not found: $MODEM"
exit 1
fi

stty -F $MODEM $BAUD pass8 raw crtscts clocal

echo "Wait modem to boot"
chat -t5 "" "AT" "OK" <$MODEM >$MODEM || true

echo "Attach CMUX channel to modem..."
ldattach -c $'AT#XCMUX=1\r' GSM0710 $MODEM

sleep 1
stty -F $AT_CMUX clocal

echo "Connect and wait for PPP link..."
test -c $AT_CMUX
chat $CHATOPT -t60 "" "AT+CFUN=1" "OK" "\c" "#XPPP: 1,0" >$AT_CMUX <$AT_CMUX

pppd $PPP_CMUX noauth novj nodeflate nobsdcomp debug noipdefault passive +ipv6 \
noremoteip local linkname nrf91 defaultroute defaultroute-metric -1
29 changes: 29 additions & 0 deletions applications/serial_lte_modem/scripts/slm_stop_ppp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash -u
#
# Copyright (c) 2025 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause

#
# Script to stop PPP link inside CMUX channel
# using Serial LTE Modem
#

MODEM=/dev/ttyACM0
BAUD=115200
PPP_CMUX=/dev/gsmtty2
AT_CMUX=/dev/gsmtty1
CHATOPT="-vs"

if [[ ! -c $AT_CMUX ]]; then
echo "AT CMUX channel not found: $AT_CMUX"
pkill pppd
pkill ldattach
exit 1
fi

chat $CHATOPT -t30 "" "AT+CFUN=0" "#XPPP: 0,0" >$AT_CMUX <$AT_CMUX

sleep 1
test -f /var/run/ppp-nrf91.pid && kill $(head -1 </var/run/ppp-nrf91.pid)
pkill ldattach
8 changes: 4 additions & 4 deletions applications/serial_lte_modem/src/slm_cmux.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ static struct {
struct modem_pipe *uart_pipe;
bool uart_pipe_open;
struct modem_backend_uart uart_backend;
uint8_t uart_backend_receive_buf[RECV_BUF_LEN];
uint8_t uart_backend_transmit_buf[TRANSMIT_BUF_LEN];
uint8_t uart_backend_receive_buf[CONFIG_SLM_CMUX_UART_BUFFER_SIZE];
uint8_t uart_backend_transmit_buf[CONFIG_SLM_CMUX_UART_BUFFER_SIZE];

/* CMUX */
struct modem_cmux instance;
uint8_t cmux_receive_buf[RECV_BUF_LEN];
uint8_t cmux_transmit_buf[TRANSMIT_BUF_LEN];
uint8_t cmux_receive_buf[CONFIG_MODEM_CMUX_WORK_BUFFER_SIZE];
uint8_t cmux_transmit_buf[CONFIG_MODEM_CMUX_WORK_BUFFER_SIZE];

/* CMUX channels (Data Link Connection Identifier); index = address - 1 */
struct cmux_dlci {
Expand Down