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-03-11 06:50:38

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

Generated by: LCOV version 2.0-1