Skip to content

Commit

Permalink
applications: serial_lte_modem: SLM UART refactoring
Browse files Browse the repository at this point in the history
Following changes have been made:
- RX operations to work as data streams. RX is never disabled unless it
  runs out of buffers. Multiple AT commands can be bundled together
  instead of waiting for OK for all of them.

- TX operations to work as data streams. Multiple TX messages will be
  bundled together. This is not backwards compatible and will break the
  RX of clients, which expect singular UART RX response to include one
  AT-command response. It can include several or partial responses as
  well as data in datamode. However, everything is transmitted in the
  order that it is triggered in SLM and the various buffer corruptions
  are fixed.

- Hardware flow control is on by default. SLM can operate without, if
  sufficient buffer sizes are defined. Dynamically setting HWFC is
  removed, it has not worked for a while and we should follow the
  device tree. IDLE mode GPIO changed to be edge triggered.
  Previously it was level triggered and caused a stack overflow.

- Add handling for data, which is larger than datamode buffer.
  Callbacks which are capable of sending data as stream, are able to
  send ~any size data. Callbacks which are not, will stop sending with
  failure.

Signed-off-by: Markus Lassila <markus.lassila@nordicsemi.no>
  • Loading branch information
MarkusLassila authored and rlubos committed Jul 4, 2023
1 parent c3a9f8a commit 649d62b
Show file tree
Hide file tree
Showing 24 changed files with 1,137 additions and 758 deletions.
1 change: 1 addition & 0 deletions applications/serial_lte_modem/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ target_sources(app PRIVATE src/slm_at_tcp_proxy.c)
target_sources(app PRIVATE src/slm_at_udp_proxy.c)
target_sources(app PRIVATE src/slm_at_icmp.c)
target_sources(app PRIVATE src/slm_at_fota.c)
target_sources(app PRIVATE src/slm_uart_handler.c)
# NORDIC SDK APP END
target_sources_ifdef(CONFIG_SLM_SMS app PRIVATE src/slm_at_sms.c)
target_sources_ifdef(CONFIG_SLM_NATIVE_TLS app PRIVATE src/slm_native_tls.c)
Expand Down
31 changes: 31 additions & 0 deletions applications/serial_lte_modem/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,30 @@ choice
bool "CR+LF termination"
endchoice

#
# UART buffers
#
config SLM_UART_RX_BUF_COUNT
int "Receive buffers for UART"
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.

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.

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.

#
# GPIO wakeup
#
Expand Down Expand Up @@ -115,6 +139,13 @@ config SLM_DATAMODE_URC
help
Report result of data mode sending

config SLM_DATAMODE_BUF_SIZE
int "Buffer size for data mode"
range 1024 8192
default 4096
help
Size of the buffer for data received in data mode.

#
# Configurable services
#
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

&uart0 {
status = "okay";
hw-flow-control;
};

&uart2 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

&uart0 {
status = "okay";
hw-flow-control;
};

&uart2 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
};
};

&uart0 {
status = "okay";
hw-flow-control;
};

&uart2 {
status="disabled";
};
Expand Down
46 changes: 5 additions & 41 deletions applications/serial_lte_modem/doc/Generic_AT_commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -302,19 +302,11 @@ The ``#XSLMUART`` command manages the UART settings.
Set command
-----------

The set command changes the UART baud rate and hardware flow control settings.
Hardware flow control settings can be changed only if ``hw-flow-control`` is enabled in device tree.
These settings are stored in the flash memory and applied during the application startup.
The set command changes the UART baud rate setting.
This setting is stored in the flash memory and applied during the application startup.

Syntax
~~~~~~

The following is the syntax when ``hw-flow-control`` is enabled in device tree.:
::

#XSLMUART[=<baud_rate>,<hwfc>]

The following is the syntax when ``hw-flow-control`` is disabled in device tree.:
::

#XSLMUART[=<baud_rate>]
Expand All @@ -341,17 +333,6 @@ When not specified, it is set to the last value set for the variable and stored
If there is no value stored for the variable, it is set to its default value.
If not specified, the previous value is used.

The ``<hwfc>`` parameter accepts the following integer values:

* ``0`` - Disable UART hardware flow control.

* ``1`` - Enable UART hardware flow control.
In this mode, SLM configures both the RTS and the CTS pins according to the device-tree file.

Its default value is ``1``.
When not specified, it is set to the last value set for the variable and stored in the flash memory.
If there is no value stored for the variable, it is set to its default value.

Response syntax
~~~~~~~~~~~~~~~

Expand All @@ -362,7 +343,7 @@ Example

::

AT#XSLMUART=1000000,1
AT#XSLMUART=1000000
OK

Read command
Expand All @@ -382,15 +363,15 @@ Response syntax

::

#XSLMUART: <baud_rate>,<hwfc>
#XSLMUART: <baud_rate>

Example
~~~~~~~

::

AT#XSLMUART?
#XSLMUART: 115200,1
#XSLMUART: 115200
OK

Test command
Expand All @@ -408,30 +389,13 @@ Syntax
Response syntax
~~~~~~~~~~~~~~~

The following is the syntax when ``hw-flow-control`` is enabled in device tree:

::

#XSLMUART: (list of the available baud rate options),(disable or enable hwfc)

The following is the syntax when ``hw-flow-control`` is disabled in device tree:

::

#XSLMUART: (list of the available baud rate options)

Example
~~~~~~~

The following is an example when ``hw-flow-control`` is enabled in device tree:

::

AT#XSLMUART=?
#XSLMUART: (1200,2400,4800,9600,14400,19200,38400,57600,115200,230400,460800,921600,1000000),(0,1)

The following is an example when ``hw-flow-control`` is disabled in device tree.:

::

AT#XSLMUART=?
Expand Down
50 changes: 32 additions & 18 deletions applications/serial_lte_modem/doc/slm_data_mode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,46 +72,54 @@ To exit data mode, the MCU sends the termination command set by the :ref:`CONFIG
The pattern string could be sent alone or as an affix to the data.
The pattern string must be sent in full.

.. note::
Some terminal software, like LTE Link Monitor, always appends an AT command terminator (for example ``<CR><LF>``) to uplink data.
This makes it unsuitable for data mode as exiting data mode can't work.

If the current sending function fails, the SLM application exits data mode and returns the error code as ``#XDATAMODE: <error>``.
The ``<error>`` value is a negative integer.

The SLM application also exits data mode automatically in the following scenarios:

* The TCP server is stopped.
* The remote server disconnects the TCP client.
* The TCP client disconnects from the remote server due to an error.
* The UDP client disconnects from the remote server due to an error.

When exiting data mode, the SLM application sends ``#XDATAMODE: 0`` as an unsolicited notification.

After exiting data mode, the SLM application returns to the AT command mode.

.. note::
Previously, the SLM application exited data mode automatically in the following scenarios:

* The TCP server is stopped.
* The remote server disconnects the TCP client.
* The TCP client disconnects from the remote server due to an error.
* The UDP client disconnects from the remote server due to an error.

Currently, in these scenarios, the SLM application moves to a state where the data received from UART is dropped until the MCU sends the termination command.

Triggering the transmission
===========================

The SLM application buffers all the arbitrary data received from the UART bus before initiating the transmission.

The transmission of the buffered data to the LTE network is triggered by the time limit when the defined inactivity timer times out.
The transmission of the buffered data to the LTE network is triggered in the following scenarios:

* Time limit when the defined inactivity timer times out.
* Reception of the termination string.
* Filling of the data mode buffer.

If there is no time limit configured, the minimum required value applies.
For more information, see the `Data mode control #XDATACTRL`_ command.

Flow control in data mode
=========================

When SLM fills its receiving buffer, the MCU must impose flow control to the SLM over the UART interface to avoid any buffer overflow.
Otherwise, if SLM imposes flow control, it disables the UART reception when it runs out of space in the buffer, potentially leading to data loss.

SLM reenables UART receptions after the transmission of the data previously received has freed up buffer space.
The buffer size is set to 3884 bytes by default.
When SLM fills its UART receive buffers, it enables the UART hardware flow control, which disables UART reception.
SLM reenables UART reception when the data has been moved to the data mode buffer.
If the data mode buffer fills, the data are transmitted to the LTE network.

.. note::
There is no unsolicited notification defined for this event.
UART hardware flow control is responsible for imposing and revoking flow control.

The data mode buffer size is controlled by :ref:`CONFIG_SLM_DATAMODE_BUF_SIZE <CONFIG_SLM_DATAMODE_BUF_SIZE>`.

.. note::
The whole buffer is sent in a single operation.
When transmitting UDP packets, only one complete packet must reside in the data mode buffer at any time.

Configuration options
*********************

Expand All @@ -130,6 +138,12 @@ CONFIG_SLM_DATAMODE_URC - Send URC in data mode
The MCU could use this URC for application-level uplink flow control.
It is not selected by default.

.. _CONFIG_SLM_DATAMODE_BUF_SIZE:

CONFIG_SLM_DATAMODE_BUF_SIZE - Buffer size for data mode
This option defines the buffer size for the data mode.
The default value is 4096.

Data mode AT commands
*********************

Expand Down Expand Up @@ -157,7 +171,7 @@ Syntax

* The ``<time_limit>`` parameter sets the timeout value in milliseconds.
The default value is the minimum required value, based on the configured UART baud rate.
This value must be long enough to allow for the transmission of one DMA block size of data (hardcoded to 256 bytes).
This value must be long enough to allow for a DMA transmission of an UART receive (RX) buffer (:ref:`CONFIG_SLM_UART_RX_BUF_SIZE <CONFIG_SLM_UART_RX_BUF_SIZE>`).

Read command
------------
Expand Down
18 changes: 18 additions & 0 deletions applications/serial_lte_modem/doc/slm_description.rst
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,24 @@ CONFIG_SLM_HTTPC - HTTP client support in SLM
CONFIG_SLM_TWI - TWI support in SLM
This option enables additional AT commands for using the TWI service.

.. _CONFIG_SLM_UART_RX_BUF_COUNT:

CONFIG_SLM_UART_RX_BUF_COUNT - Receive buffers for UART.
This option defines the amount of buffers for receiving (RX) UART traffic.
The default value is 3.

.. _CONFIG_SLM_UART_RX_BUF_SIZE:

CONFIG_SLM_UART_RX_BUF_SIZE - Receive buffer size for UART.
This option defines the size of a single buffer for receiving (RX) UART traffic.
The default value is 256.

.. _CONFIG_SLM_UART_TX_BUF_SIZE:

CONFIG_SLM_UART_TX_BUF_SIZE - Send buffer size for UART.
This option defines the size of the buffer for sending (TX) UART traffic.
The default value is 256.

Additional configuration
========================

Expand Down
3 changes: 3 additions & 0 deletions applications/serial_lte_modem/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,6 @@ CONFIG_SLM_LOG_LEVEL_INF=y
CONFIG_SLM_EXTERNAL_XTAL=n
CONFIG_SLM_START_SLEEP=n
CONFIG_SLM_DATAMODE_URC=n

# Debug configurations
#CONFIG_LOG_PRINTK=n
28 changes: 18 additions & 10 deletions applications/serial_lte_modem/src/ftp_c/slm_at_ftp.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ typedef struct ftp_op_list {
static bool ftp_verbose_on;
static char filepath[SLM_MAX_FILEPATH];
static int sz_filepath;
static int (*ftp_data_mode_handler)(const uint8_t *data, int len);
static int (*ftp_data_mode_handler)(const uint8_t *data, int len, uint8_t flags);

/** forward declaration of cmd handlers **/
static int do_ftp_close(void);
Expand Down Expand Up @@ -150,7 +150,7 @@ void ftp_ctrl_callback(const uint8_t *msg, uint16_t len)
}
break;
}
if (ftp_data_mode_handler && exit_datamode(-EAGAIN)) {
if (ftp_data_mode_handler && exit_datamode_handler(-EAGAIN)) {
ftp_data_mode_handler = NULL;
}
return;
Expand Down Expand Up @@ -446,13 +446,13 @@ static int do_ftp_get(void)
}
}

static int ftp_datamode_callback(uint8_t op, const uint8_t *data, int len)
static int ftp_datamode_callback(uint8_t op, const uint8_t *data, int len, uint8_t flags)
{
int ret = 0;

if (op == DATAMODE_SEND) {
if (ftp_data_mode_handler) {
ret = ftp_data_mode_handler(data, len);
ret = ftp_data_mode_handler(data, len, flags);
LOG_INF("datamode send: %d", ret);
} else {
LOG_ERR("no datamode send handler");
Expand All @@ -465,14 +465,17 @@ static int ftp_datamode_callback(uint8_t op, const uint8_t *data, int len)
}

/* FTP PUT data mode handler */
static int ftp_put_handler(const uint8_t *data, int len)
static int ftp_put_handler(const uint8_t *data, int len, uint8_t flags)
{
int ret = -1;

if (strlen(filepath) > 0 && data != NULL) {
ret = ftp_put(filepath, data, len, FTP_PUT_NORMAL);
if (ret != FTP_CODE_226) {
(void) exit_datamode(-EAGAIN);
(void) exit_datamode_handler(-EAGAIN);
} else if ((flags & SLM_DATAMODE_FLAGS_MORE_DATA) != 0) {
LOG_ERR("Datamode buffer overflow");
(void)exit_datamode_handler(-EOVERFLOW);
}
}

Expand Down Expand Up @@ -514,14 +517,17 @@ static int do_ftp_put(void)
}

/* FTP UPUT data mode handler */
static int ftp_uput_handler(const uint8_t *data, int len)
static int ftp_uput_handler(const uint8_t *data, int len, uint8_t flags)
{
int ret = -1;

if (data != NULL) {
ret = ftp_put(NULL, data, len, FTP_PUT_UNIQUE);
if (ret != FTP_CODE_226) {
(void) exit_datamode(-EAGAIN);
(void)exit_datamode_handler(-EAGAIN);
} else if ((flags & SLM_DATAMODE_FLAGS_MORE_DATA) != 0) {
LOG_ERR("Datamode buffer overflow");
(void)exit_datamode_handler(-EOVERFLOW);
}
}

Expand Down Expand Up @@ -556,11 +562,13 @@ static int do_ftp_uput(void)
return ret;
}

/* FTP UPUT data mode handler */
static int ftp_mput_handler(const uint8_t *data, int len)
/* FTP MPUT data mode handler */
static int ftp_mput_handler(const uint8_t *data, int len, uint8_t flags)
{
int ret = -1;

ARG_UNUSED(flags);

if (strlen(filepath) > 0 && data != NULL) {
ret = ftp_put(filepath, data, len, FTP_PUT_APPEND);
}
Expand Down
Loading

0 comments on commit 649d62b

Please sign in to comment.