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-09-05 16:43:28

            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              : enum modem_cmux_state {
      61              :         MODEM_CMUX_STATE_DISCONNECTED = 0,
      62              :         MODEM_CMUX_STATE_CONNECTING,
      63              :         MODEM_CMUX_STATE_CONNECTED,
      64              :         MODEM_CMUX_STATE_DISCONNECTING,
      65              : };
      66              : 
      67              : enum modem_cmux_receive_state {
      68              :         MODEM_CMUX_RECEIVE_STATE_SOF = 0,
      69              :         MODEM_CMUX_RECEIVE_STATE_RESYNC,
      70              :         MODEM_CMUX_RECEIVE_STATE_ADDRESS,
      71              :         MODEM_CMUX_RECEIVE_STATE_ADDRESS_CONT,
      72              :         MODEM_CMUX_RECEIVE_STATE_CONTROL,
      73              :         MODEM_CMUX_RECEIVE_STATE_LENGTH,
      74              :         MODEM_CMUX_RECEIVE_STATE_LENGTH_CONT,
      75              :         MODEM_CMUX_RECEIVE_STATE_DATA,
      76              :         MODEM_CMUX_RECEIVE_STATE_FCS,
      77              :         MODEM_CMUX_RECEIVE_STATE_DROP,
      78              :         MODEM_CMUX_RECEIVE_STATE_EOF,
      79              : };
      80              : 
      81              : enum modem_cmux_dlci_state {
      82              :         MODEM_CMUX_DLCI_STATE_CLOSED,
      83              :         MODEM_CMUX_DLCI_STATE_OPENING,
      84              :         MODEM_CMUX_DLCI_STATE_OPEN,
      85              :         MODEM_CMUX_DLCI_STATE_CLOSING,
      86              : };
      87              : 
      88              : struct modem_cmux_dlci {
      89              :         sys_snode_t node;
      90              : 
      91              :         /* Pipe */
      92              :         struct modem_pipe pipe;
      93              : 
      94              :         /* Context */
      95              :         uint16_t dlci_address;
      96              :         struct modem_cmux *cmux;
      97              : 
      98              :         /* Receive buffer */
      99              :         struct ring_buf receive_rb;
     100              :         struct k_mutex receive_rb_lock;
     101              : 
     102              :         /* Work */
     103              :         struct k_work_delayable open_work;
     104              :         struct k_work_delayable close_work;
     105              : 
     106              :         /* State */
     107              :         enum modem_cmux_dlci_state state;
     108              : 
     109              :         /* Statistics */
     110              : #if CONFIG_MODEM_STATS
     111              :         struct modem_stats_buffer receive_buf_stats;
     112              : #endif
     113              : };
     114              : 
     115              : struct modem_cmux_frame {
     116              :         uint8_t dlci_address;
     117              :         bool cr;
     118              :         bool pf;
     119              :         uint8_t type;
     120              :         const uint8_t *data;
     121              :         uint16_t data_len;
     122              : };
     123              : 
     124              : struct modem_cmux_work {
     125              :         struct k_work_delayable dwork;
     126              :         struct modem_cmux *cmux;
     127              : };
     128              : 
     129              : struct modem_cmux {
     130              :         /* Bus pipe */
     131              :         struct modem_pipe *pipe;
     132              : 
     133              :         /* Event handler */
     134              :         modem_cmux_callback callback;
     135              :         void *user_data;
     136              : 
     137              :         /* DLCI channel contexts */
     138              :         sys_slist_t dlcis;
     139              : 
     140              :         /* State */
     141              :         enum modem_cmux_state state;
     142              :         bool flow_control_on;
     143              : 
     144              :         /* Work lock */
     145              :         bool attached;
     146              :         struct k_spinlock work_lock;
     147              : 
     148              :         /* Receive state*/
     149              :         enum modem_cmux_receive_state receive_state;
     150              : 
     151              :         /* Receive buffer */
     152              :         uint8_t *receive_buf;
     153              :         uint16_t receive_buf_size;
     154              :         uint16_t receive_buf_len;
     155              : 
     156              :         uint8_t work_buf[CONFIG_MODEM_CMUX_WORK_BUFFER_SIZE];
     157              : 
     158              :         /* Transmit buffer */
     159              :         struct ring_buf transmit_rb;
     160              :         struct k_mutex transmit_rb_lock;
     161              : 
     162              :         /* Received frame */
     163              :         struct modem_cmux_frame frame;
     164              :         uint8_t frame_header[5];
     165              :         uint16_t frame_header_len;
     166              : 
     167              :         /* Work */
     168              :         struct k_work_delayable receive_work;
     169              :         struct k_work_delayable transmit_work;
     170              :         struct k_work_delayable connect_work;
     171              :         struct k_work_delayable disconnect_work;
     172              : 
     173              :         /* Synchronize actions */
     174              :         struct k_event event;
     175              : 
     176              :         /* Statistics */
     177              : #if CONFIG_MODEM_STATS
     178              :         struct modem_stats_buffer receive_buf_stats;
     179              :         struct modem_stats_buffer transmit_buf_stats;
     180              : #endif
     181              : };
     182              : 
     183              : /**
     184              :  * @endcond
     185              :  */
     186              : 
     187              : /**
     188              :  * @brief Contains CMUX instance configuration data
     189              :  */
     190            1 : struct modem_cmux_config {
     191              :         /** Invoked when event occurs */
     192            1 :         modem_cmux_callback callback;
     193              :         /** Free to use pointer passed to event handler when invoked */
     194            1 :         void *user_data;
     195              :         /** Receive buffer */
     196            1 :         uint8_t *receive_buf;
     197              :         /** Size of receive buffer in bytes [127, ...] */
     198            1 :         uint16_t receive_buf_size;
     199              :         /** Transmit buffer */
     200            1 :         uint8_t *transmit_buf;
     201              :         /** Size of transmit buffer in bytes [149, ...] */
     202            1 :         uint16_t transmit_buf_size;
     203              : };
     204              : 
     205              : /**
     206              :  * @brief Initialize CMUX instance
     207              :  * @param cmux CMUX instance
     208              :  * @param config Configuration to apply to CMUX instance
     209              :  */
     210            1 : void modem_cmux_init(struct modem_cmux *cmux, const struct modem_cmux_config *config);
     211              : 
     212              : /**
     213              :  * @brief CMUX DLCI configuration
     214              :  */
     215            1 : struct modem_cmux_dlci_config {
     216              :         /** DLCI channel address */
     217            1 :         uint8_t dlci_address;
     218              :         /** Receive buffer used by pipe */
     219            1 :         uint8_t *receive_buf;
     220              :         /** Size of receive buffer used by pipe [127, ...] */
     221            1 :         uint16_t receive_buf_size;
     222              : };
     223              : 
     224              : /**
     225              :  * @brief Initialize DLCI instance and register it with CMUX instance
     226              :  *
     227              :  * @param cmux CMUX instance which the DLCI will be registered to
     228              :  * @param dlci DLCI instance which will be registered and configured
     229              :  * @param config Configuration to apply to DLCI instance
     230              :  */
     231            1 : struct modem_pipe *modem_cmux_dlci_init(struct modem_cmux *cmux, struct modem_cmux_dlci *dlci,
     232              :                                         const struct modem_cmux_dlci_config *config);
     233              : 
     234              : /**
     235              :  * @brief Attach CMUX instance to pipe
     236              :  *
     237              :  * @param cmux CMUX instance
     238              :  * @param pipe Pipe instance to attach CMUX instance to
     239              :  */
     240            1 : int modem_cmux_attach(struct modem_cmux *cmux, struct modem_pipe *pipe);
     241              : 
     242              : /**
     243              :  * @brief Connect CMUX instance
     244              :  *
     245              :  * @details This will send a CMUX connect request to target on the serial bus. If successful,
     246              :  * DLCI channels can be now be opened using modem_pipe_open()
     247              :  *
     248              :  * @param cmux CMUX instance
     249              :  *
     250              :  * @note When connected, the bus pipe must not be used directly
     251              :  */
     252            1 : int modem_cmux_connect(struct modem_cmux *cmux);
     253              : 
     254              : /**
     255              :  * @brief Connect CMUX instance asynchronously
     256              :  *
     257              :  * @details This will send a CMUX connect request to target on the serial bus. If successful,
     258              :  * DLCI channels can be now be opened using modem_pipe_open().
     259              :  *
     260              :  * @param cmux CMUX instance
     261              :  *
     262              :  * @note When connected, the bus pipe must not be used directly
     263              :  */
     264            1 : int modem_cmux_connect_async(struct modem_cmux *cmux);
     265              : 
     266              : /**
     267              :  * @brief Close down and disconnect CMUX instance
     268              :  *
     269              :  * @details This will close all open DLCI channels, and close down the CMUX connection.
     270              :  *
     271              :  * @param cmux CMUX instance
     272              :  *
     273              :  * @note The bus pipe must be released using modem_cmux_release() after disconnecting
     274              :  * before being reused.
     275              :  */
     276            1 : int modem_cmux_disconnect(struct modem_cmux *cmux);
     277              : 
     278              : /**
     279              :  * @brief Close down and disconnect CMUX instance asynchronously
     280              :  *
     281              :  * @details This will close all open DLCI channels, and close down the CMUX connection.
     282              :  *
     283              :  * @param cmux CMUX instance
     284              :  *
     285              :  * @note The bus pipe must be released using modem_cmux_release() after disconnecting
     286              :  * before being reused.
     287              :  */
     288            1 : int modem_cmux_disconnect_async(struct modem_cmux *cmux);
     289              : 
     290              : /**
     291              :  * @brief Release CMUX instance from pipe
     292              :  *
     293              :  * @details Releases the pipe and hard resets the CMUX instance internally. CMUX should
     294              :  * be disconnected using modem_cmux_disconnect().
     295              :  *
     296              :  * @param cmux CMUX instance
     297              :  *
     298              :  * @note The bus pipe can be used directly again after CMUX instance is released.
     299              :  */
     300            1 : void modem_cmux_release(struct modem_cmux *cmux);
     301              : 
     302              : /**
     303              :  * @}
     304              :  */
     305              : 
     306              : #ifdef __cplusplus
     307              : }
     308              : #endif
     309              : 
     310              : #endif /* ZEPHYR_MODEM_CMUX_ */
        

Generated by: LCOV version 2.0-1