LCOV - code coverage report
Current view: top level - zephyr/modem - cmux.h Coverage Total Hit
Test: new.info Lines: 86.4 % 22 19
Test Date: 2025-10-20 12:20:01

            Line data    Source code
       1            0 : /*
       2              :  * Copyright (c) 2022 Trackunit Corporation
       3              :  *
       4              :  * SPDX-License-Identifier: Apache-2.0
       5              :  */
       6              : 
       7              : /*
       8              :  * This library uses CMUX to create multiple data channels, called DLCIs, on a single serial bus.
       9              :  * Each DLCI has an address from 1 to 63. DLCI address 0 is reserved for control commands.
      10              :  *
      11              :  * Design overview:
      12              :  *
      13              :  *     DLCI1 <-----------+                              +-------> DLCI1
      14              :  *                       v                              v
      15              :  *     DLCI2 <---> CMUX instance <--> Serial bus <--> Client <--> DLCI2
      16              :  *                       ^                              ^
      17              :  *     DLCI3 <-----------+                              +-------> DLCI3
      18              :  *
      19              :  * Writing to and from the CMUX instances is done using the modem_pipe API.
      20              :  */
      21              : 
      22              : #include <zephyr/kernel.h>
      23              : #include <zephyr/types.h>
      24              : #include <zephyr/sys/ring_buffer.h>
      25              : #include <zephyr/sys/atomic.h>
      26              : 
      27              : #include <zephyr/modem/pipe.h>
      28              : #include <zephyr/modem/stats.h>
      29              : 
      30              : #ifndef ZEPHYR_MODEM_CMUX_
      31              : #define ZEPHYR_MODEM_CMUX_
      32              : 
      33              : #ifdef __cplusplus
      34              : extern "C" {
      35              : #endif
      36              : 
      37              : /**
      38              :  * @brief Modem CMUX
      39              :  * @defgroup modem_cmux Modem CMUX
      40              :  * @since 3.5
      41              :  * @version 1.0.0
      42              :  * @ingroup modem
      43              :  * @{
      44              :  */
      45              : 
      46              : struct modem_cmux;
      47              : 
      48            0 : enum modem_cmux_event {
      49              :         MODEM_CMUX_EVENT_CONNECTED = 0,
      50              :         MODEM_CMUX_EVENT_DISCONNECTED,
      51              : };
      52              : 
      53            0 : typedef void (*modem_cmux_callback)(struct modem_cmux *cmux, enum modem_cmux_event event,
      54              :                                     void *user_data);
      55              : 
      56              : /**
      57              :  * @cond INTERNAL_HIDDEN
      58              :  */
      59              : 
      60              : #if CONFIG_MODEM_CMUX_MTU > 127
      61              : #define MODEM_CMUX_HEADER_SIZE                  7
      62              : #else
      63              : #define MODEM_CMUX_HEADER_SIZE                  6
      64              : #endif
      65              : 
      66              : 
      67              : /* Total size of the CMUX work buffers */
      68              : #define MODEM_CMUX_WORK_BUFFER_SIZE (CONFIG_MODEM_CMUX_MTU + MODEM_CMUX_HEADER_SIZE + \
      69              :                                      CONFIG_MODEM_CMUX_WORK_BUFFER_SIZE_EXTRA)
      70              : 
      71              : enum modem_cmux_state {
      72              :         MODEM_CMUX_STATE_DISCONNECTED = 0,
      73              :         MODEM_CMUX_STATE_CONNECTING,
      74              :         MODEM_CMUX_STATE_CONNECTED,
      75              :         MODEM_CMUX_STATE_DISCONNECTING,
      76              : };
      77              : 
      78              : enum modem_cmux_receive_state {
      79              :         MODEM_CMUX_RECEIVE_STATE_SOF = 0,
      80              :         MODEM_CMUX_RECEIVE_STATE_RESYNC,
      81              :         MODEM_CMUX_RECEIVE_STATE_ADDRESS,
      82              :         MODEM_CMUX_RECEIVE_STATE_ADDRESS_CONT,
      83              :         MODEM_CMUX_RECEIVE_STATE_CONTROL,
      84              :         MODEM_CMUX_RECEIVE_STATE_LENGTH,
      85              :         MODEM_CMUX_RECEIVE_STATE_LENGTH_CONT,
      86              :         MODEM_CMUX_RECEIVE_STATE_DATA,
      87              :         MODEM_CMUX_RECEIVE_STATE_FCS,
      88              :         MODEM_CMUX_RECEIVE_STATE_EOF,
      89              : };
      90              : 
      91              : enum modem_cmux_dlci_state {
      92              :         MODEM_CMUX_DLCI_STATE_CLOSED,
      93              :         MODEM_CMUX_DLCI_STATE_OPENING,
      94              :         MODEM_CMUX_DLCI_STATE_OPEN,
      95              :         MODEM_CMUX_DLCI_STATE_CLOSING,
      96              : };
      97              : 
      98              : struct modem_cmux_dlci {
      99              :         sys_snode_t node;
     100              : 
     101              :         /* Pipe */
     102              :         struct modem_pipe pipe;
     103              : 
     104              :         /* Context */
     105              :         uint16_t dlci_address;
     106              :         struct modem_cmux *cmux;
     107              : 
     108              :         /* Receive buffer */
     109              :         struct ring_buf receive_rb;
     110              :         struct k_mutex receive_rb_lock;
     111              : 
     112              :         /* Work */
     113              :         struct k_work_delayable open_work;
     114              :         struct k_work_delayable close_work;
     115              : 
     116              :         /* State */
     117              :         enum modem_cmux_dlci_state state;
     118              : 
     119              :         /* Statistics */
     120              : #if CONFIG_MODEM_STATS
     121              :         struct modem_stats_buffer receive_buf_stats;
     122              : #endif
     123              : };
     124              : 
     125              : struct modem_cmux_frame {
     126              :         uint8_t dlci_address;
     127              :         bool cr;
     128              :         bool pf;
     129              :         uint8_t type;
     130              :         const uint8_t *data;
     131              :         uint16_t data_len;
     132              : };
     133              : 
     134              : struct modem_cmux_work {
     135              :         struct k_work_delayable dwork;
     136              :         struct modem_cmux *cmux;
     137              : };
     138              : 
     139              : struct modem_cmux {
     140              :         /* Bus pipe */
     141              :         struct modem_pipe *pipe;
     142              : 
     143              :         /* Event handler */
     144              :         modem_cmux_callback callback;
     145              :         void *user_data;
     146              : 
     147              :         /* DLCI channel contexts */
     148              :         sys_slist_t dlcis;
     149              : 
     150              :         /* State */
     151              :         enum modem_cmux_state state;
     152              :         bool flow_control_on : 1;
     153              :         bool initiator : 1;
     154              : 
     155              :         /* Work lock */
     156              :         bool attached : 1;
     157              :         struct k_spinlock work_lock;
     158              : 
     159              :         /* Receive state*/
     160              :         enum modem_cmux_receive_state receive_state;
     161              : 
     162              :         /* Receive buffer */
     163              :         uint8_t *receive_buf;
     164              :         uint16_t receive_buf_size;
     165              :         uint16_t receive_buf_len;
     166              : 
     167              :         uint8_t work_buf[MODEM_CMUX_WORK_BUFFER_SIZE];
     168              : 
     169              :         /* Transmit buffer */
     170              :         struct ring_buf transmit_rb;
     171              :         struct k_mutex transmit_rb_lock;
     172              : 
     173              :         /* Received frame */
     174              :         struct modem_cmux_frame frame;
     175              :         uint8_t frame_header[5];
     176              :         uint16_t frame_header_len;
     177              : 
     178              :         /* Work */
     179              :         struct k_work_delayable receive_work;
     180              :         struct k_work_delayable transmit_work;
     181              :         struct k_work_delayable connect_work;
     182              :         struct k_work_delayable disconnect_work;
     183              : 
     184              :         /* Synchronize actions */
     185              :         struct k_event event;
     186              : 
     187              :         /* Statistics */
     188              : #if CONFIG_MODEM_STATS
     189              :         struct modem_stats_buffer receive_buf_stats;
     190              :         struct modem_stats_buffer transmit_buf_stats;
     191              : #endif
     192              : };
     193              : 
     194              : /**
     195              :  * @endcond
     196              :  */
     197              : 
     198              : /**
     199              :  * @brief Contains CMUX instance configuration data
     200              :  */
     201            1 : struct modem_cmux_config {
     202              :         /** Invoked when event occurs */
     203            1 :         modem_cmux_callback callback;
     204              :         /** Free to use pointer passed to event handler when invoked */
     205            1 :         void *user_data;
     206              :         /** Receive buffer */
     207            1 :         uint8_t *receive_buf;
     208              :         /** Size of receive buffer in bytes [127, ...] */
     209            1 :         uint16_t receive_buf_size;
     210              :         /** Transmit buffer */
     211            1 :         uint8_t *transmit_buf;
     212              :         /** Size of transmit buffer in bytes [149, ...] */
     213            1 :         uint16_t transmit_buf_size;
     214              : };
     215              : 
     216              : /**
     217              :  * @brief Initialize CMUX instance
     218              :  * @param cmux CMUX instance
     219              :  * @param config Configuration to apply to CMUX instance
     220              :  */
     221            1 : void modem_cmux_init(struct modem_cmux *cmux, const struct modem_cmux_config *config);
     222              : 
     223              : /**
     224              :  * @brief CMUX DLCI configuration
     225              :  */
     226            1 : struct modem_cmux_dlci_config {
     227              :         /** DLCI channel address */
     228            1 :         uint8_t dlci_address;
     229              :         /** Receive buffer used by pipe */
     230            1 :         uint8_t *receive_buf;
     231              :         /** Size of receive buffer used by pipe [127, ...] */
     232            1 :         uint16_t receive_buf_size;
     233              : };
     234              : 
     235              : /**
     236              :  * @brief Initialize DLCI instance and register it with CMUX instance
     237              :  *
     238              :  * @param cmux CMUX instance which the DLCI will be registered to
     239              :  * @param dlci DLCI instance which will be registered and configured
     240              :  * @param config Configuration to apply to DLCI instance
     241              :  */
     242            1 : struct modem_pipe *modem_cmux_dlci_init(struct modem_cmux *cmux, struct modem_cmux_dlci *dlci,
     243              :                                         const struct modem_cmux_dlci_config *config);
     244              : 
     245              : /**
     246              :  * @brief Attach CMUX instance to pipe
     247              :  *
     248              :  * @param cmux CMUX instance
     249              :  * @param pipe Pipe instance to attach CMUX instance to
     250              :  */
     251            1 : int modem_cmux_attach(struct modem_cmux *cmux, struct modem_pipe *pipe);
     252              : 
     253              : /**
     254              :  * @brief Connect CMUX instance
     255              :  *
     256              :  * @details This will send a CMUX connect request to target on the serial bus. If successful,
     257              :  * DLCI channels can be now be opened using modem_pipe_open()
     258              :  *
     259              :  * @param cmux CMUX instance
     260              :  *
     261              :  * @note When connected, the bus pipe must not be used directly
     262              :  */
     263            1 : int modem_cmux_connect(struct modem_cmux *cmux);
     264              : 
     265              : /**
     266              :  * @brief Connect CMUX instance asynchronously
     267              :  *
     268              :  * @details This will send a CMUX connect request to target on the serial bus. If successful,
     269              :  * DLCI channels can be now be opened using modem_pipe_open().
     270              :  *
     271              :  * @param cmux CMUX instance
     272              :  *
     273              :  * @note When connected, the bus pipe must not be used directly
     274              :  */
     275            1 : int modem_cmux_connect_async(struct modem_cmux *cmux);
     276              : 
     277              : /**
     278              :  * @brief Close down and disconnect CMUX instance
     279              :  *
     280              :  * @details This will close all open DLCI channels, and close down the CMUX connection.
     281              :  *
     282              :  * @param cmux CMUX instance
     283              :  *
     284              :  * @note The bus pipe must be released using modem_cmux_release() after disconnecting
     285              :  * before being reused.
     286              :  */
     287            1 : int modem_cmux_disconnect(struct modem_cmux *cmux);
     288              : 
     289              : /**
     290              :  * @brief Close down and disconnect CMUX instance asynchronously
     291              :  *
     292              :  * @details This will close all open DLCI channels, and close down the CMUX connection.
     293              :  *
     294              :  * @param cmux CMUX instance
     295              :  *
     296              :  * @note The bus pipe must be released using modem_cmux_release() after disconnecting
     297              :  * before being reused.
     298              :  */
     299            1 : int modem_cmux_disconnect_async(struct modem_cmux *cmux);
     300              : 
     301              : /**
     302              :  * @brief Release CMUX instance from pipe
     303              :  *
     304              :  * @details Releases the pipe and hard resets the CMUX instance internally. CMUX should
     305              :  * be disconnected using modem_cmux_disconnect().
     306              :  *
     307              :  * @param cmux CMUX instance
     308              :  *
     309              :  * @note The bus pipe can be used directly again after CMUX instance is released.
     310              :  */
     311            1 : void modem_cmux_release(struct modem_cmux *cmux);
     312              : 
     313              : /**
     314              :  * @}
     315              :  */
     316              : 
     317              : #ifdef __cplusplus
     318              : }
     319              : #endif
     320              : 
     321              : #endif /* ZEPHYR_MODEM_CMUX_ */
        

Generated by: LCOV version 2.0-1