Skip to content

Decoupling the modem_cellular.c device driver #73722

Open
@bjarki-andreasen

Description

@bjarki-andreasen

Introduction

We need to make the modem subsystem more flexible to cover the following requirements:

  • Being able to create common modules (notice the name "common modules", it will be used later):
    • Module managing PPP networking.
    • Module Sending/receiving common 3GPP AT commands to get values like RSRQ, modem model etc.
    • Module receiving and parsing NMEA0183 GNSS messages
    • A shell for sending and receiving AT commands
    • SMS module
  • Being able to easily swap between and selectively include common, vendor specific, and OOT propriatary modules:
    • Switching between a common PPP module and a vendor specific socket offloading module.
    • Including additional OOT modules which implement application specific logic
    • Switching between a common 3GPP AT command module and one tailored to the user, possibly implementing a different API than the cellular.h API even.
  • Being able to support modems which don't implement CMUX or other multiplexing protocol. This requires being able to "borrow" the single UART for synchronous work (like sending a chat script), while always being able to receive data from the single pipe (so a module can react to URCs like +CREG=0,0).

Problem description

The current primary cellular modem driver modem_cellular.c contains quite a bit of very similar if not duplicate code, and is not easily extendable without copying the entire driver out-of-tree. It is also limited to only supporting modems which support CMUX, which is not always the case, and in some cases may not be desired even if supported.

Specific usecases

  • A user may want to send and receive an AT command or similar to the modem from the application, without modifying the modem device driver.
  • A modem may not support CMUX, but usage of common modules and user specific additions is still desired.
  • Modems may have multiple physical UARTs instead of or in combination with CMUX, reusable modules should work with either DLCI channels or additional physical UARTs (see BG95 for example)

Proposed solution

For reference, the current design of modem_cellular.c is presented here:

modem-sys-Page-3

For modems with CMUX, like the ones supported by the modem_cellular.c driver, the following diagram shows an applicable solution:

modem-sys

The new modem module modem_pipelink, makes pipes created by and managed by the device driver, available to the subsystem/application layer. The modem device driver signals when the pipes exposed through pipelinks become available (after power up and initial configuration), which triggers the common modules to open their pipe and start operating. A PR for the pipe module with an example user (AT shell) is found here #73240

Notice the scalability of the solution, as we can abstract away the type of pipe (UART/DLCI) and we can extend the number of modules interacting with the modem by simply creating more DLCI channels and pipelinks :)

For modems with CMUX, this will work great, since each pipe is completely separate, either physically or through CMUX, allowing PPP on one channel, without blocking another. However, for modems without CMUX or similar, the following diagram proposes a slightly different solution:

modem-sys-Page-2

This design replaces modem cmux with a new module modem pipemux. While modem cmux creates parallel channels, where each can transmit and receive independently, only one modem pipemux channel can transmit at a time, while all modem pipemux channels can receive simultaneously. To synchronize transmitting data between the common modules using the pipemux, a "borrow" feature must be added to the modem_pipe module. The borrow feature will be completely backwards compatible, and will use the following API:

int modem_pipe_lock(struct modem_pipe *pipe, k_timeout_t timeout);
int modem_pipe_unlock(struct modem_pipe *pipe);

Common modules will call modem_pipe_lock() on their pipe instance when they need to transmit something. With the lock held, they will perform any synchronous work they need to, like running a chat script, then they will call modem_pipe_unlock() to allow other common modules to transmit something.

Using modem_cmux, taking the lock on a pipe connected to a DLCI channel will always succeed immediately. Using modem_pipemux, taking the lock may block until it becomes available.

Summary

We can make the modem drivers flexible, allowing custom user defined logic, and creating common modules for shared features, by introducing two new modem modules, and adding a lock to the modem_pipe module. Once these modules are in, we can start creating new optimized vendor specific drivers for power management, and creating common modules for shared features like SMS, PPP, AT shell etc.

Metadata

Metadata

Labels

Type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions