1 /* 2 * Copyright (c) 2021 Demant 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #include <stdint.h> 8 #include <zephyr/types.h> 9 #include <toolchain.h> 10 11 /** Function return error codes */ 12 typedef uint8_t isoal_status_t; 13 #define ISOAL_STATUS_OK ((isoal_status_t) 0x00) /* No error */ 14 #define ISOAL_STATUS_ERR_SINK_ALLOC ((isoal_status_t) 0x01) /* Sink pool full */ 15 #define ISOAL_STATUS_ERR_SOURCE_ALLOC ((isoal_status_t) 0x02) /* Source pool full */ 16 #define ISOAL_STATUS_ERR_SDU_ALLOC ((isoal_status_t) 0x04) /* SDU allocation */ 17 #define ISOAL_STATUS_ERR_SDU_EMIT ((isoal_status_t) 0x08) /* SDU emission */ 18 19 /** Handle to a registered ISO Sub-System sink */ 20 typedef uint8_t isoal_sink_handle_t; 21 22 /** Byte length of an ISO SDU */ 23 typedef uint16_t isoal_sdu_len_t; 24 25 /** Byte length of an ISO PDU */ 26 typedef uint8_t isoal_pdu_len_t; 27 28 /** Count (ID number) of an ISO SDU */ 29 typedef uint16_t isoal_sdu_cnt_t; 30 31 /** Count (ID number) of an ISO PDU */ 32 typedef uint64_t isoal_pdu_cnt_t; 33 34 /** Ticks. Used for timestamp */ 35 typedef uint32_t isoal_time_t; 36 37 /** SDU status codes */ 38 typedef uint8_t isoal_sdu_status_t; 39 #define ISOAL_SDU_STATUS_VALID ((isoal_sdu_status_t) 0x00) 40 #define ISOAL_SDU_STATUS_ERRORS ((isoal_sdu_status_t) 0x01) 41 #define ISOAL_SDU_STATUS_LOST_DATA ((isoal_sdu_status_t) 0x02) 42 43 /** PDU status codes */ 44 typedef uint8_t isoal_pdu_status_t; 45 #define ISOAL_PDU_STATUS_VALID ((isoal_pdu_status_t) 0x00) 46 #define ISOAL_PDU_STATUS_LOST_DATA ((isoal_pdu_status_t) 0x01) 47 #define ISOAL_PDU_STATUS_ERRORS ((isoal_pdu_status_t) 0x02) 48 49 /** Production mode */ 50 typedef uint8_t isoal_production_mode_t; 51 #define ISOAL_PRODUCTION_MODE_DISABLED ((isoal_production_mode_t) 0x00) 52 #define ISOAL_PRODUCTION_MODE_ENABLED ((isoal_production_mode_t) 0x01) 53 54 55 /** 56 * Origin of {PDU or SDU}. 57 */ 58 struct isoal_rx_origin { 59 /** Originating subsystem */ 60 enum __packed { 61 ISOAL_SUBSYS_BT_LLL = 0x01, /*!< Bluetooth LLL */ 62 ISOAL_SUBSYS_BT_HCI = 0x02, /*!< Bluetooth HCI */ 63 ISOAL_SUBSYS_VS = 0xff /*!< Vendor specific */ 64 } subsys; 65 66 /** Subsystem instance */ 67 union { 68 struct { 69 uint16_t handle; /*!< BT connection handle */ 70 } bt_lll; 71 } inst; 72 }; 73 74 /** 75 * @brief ISO frame SDU buffer - typically an Audio frame buffer 76 * 77 * This provides the underlying vehicle of ISO SDU interchange through the 78 * ISO socket, the contents of which is generally an array of encoded bytes. 79 * Access and life time of this should be limited to ISO and the ISO socket. 80 * We assume no byte-fractional code words. 81 * 82 * Decoding code words to samples is the responsibility of the ISO sub system. 83 */ 84 struct isoal_sdu_buffer { 85 /** Code word buffer 86 * Type, location and alignment decided by ISO sub system 87 */ 88 void *dbuf; 89 /** Number of bytes accessible behind the dbuf pointer */ 90 isoal_sdu_len_t size; 91 }; 92 93 /** @brief Produced ISO SDU frame with associated meta data */ 94 struct isoal_sdu_produced { 95 /** Status of contents, if valid or SDU was lost */ 96 isoal_sdu_status_t status; 97 /** Regardless of status, we always have timing */ 98 isoal_time_t timestamp; 99 /** Sequence number of SDU */ 100 isoal_sdu_cnt_t seqn; 101 /** Regardless of status, we always know where the PDUs that produced 102 * this SDU, came from 103 */ 104 struct isoal_rx_origin origin; 105 /** Contents and length can only be trusted if status is valid */ 106 struct isoal_sdu_buffer contents; 107 /** Optional context to be carried from PDU at alloc-time */ 108 void *ctx; 109 }; 110 111 /** @brief ISO PDU. Covers both CIS and BIS */ 112 union isoal_pdu { 113 struct pdu_cis cis; 114 struct pdu_bis bis; 115 }; 116 117 118 /** @brief Received ISO PDU with associated meta data */ 119 struct isoal_pdu_rx { 120 /** Meta */ 121 struct node_rx_iso_meta *meta; 122 /** PDU contents and length can only be trusted if status is valid */ 123 union isoal_pdu *pdu; 124 }; 125 126 127 /* Forward declaration */ 128 struct isoal_sink; 129 130 /** 131 * @brief Callback: Request memory for a new ISO SDU buffer 132 * 133 * Proprietary ISO sub systems may have 134 * specific requirements or opinions on where to locate ISO SDUs; some 135 * memories may be faster, may be dynamically mapped in, etc. 136 * 137 * @return ISOAL_STATUS_ERR_ALLOC if size_request could not be fulfilled, otherwise 138 * ISOAL_STATUS_OK. 139 */ 140 typedef isoal_status_t (*isoal_sink_sdu_alloc_cb)( 141 /*!< [in] Sink context */ 142 const struct isoal_sink *sink_ctx, 143 /*!< [in] Received PDU */ 144 const struct isoal_pdu_rx *valid_pdu, 145 /*!< [out] Struct is modified. Must not be NULL */ 146 struct isoal_sdu_buffer *sdu_buffer 147 ); 148 149 /** 150 * @brief Callback: Push an ISO SDU into an ISO sink 151 * 152 * Call also handing back buffer ownership 153 */ 154 typedef isoal_status_t (*isoal_sink_sdu_emit_cb)( 155 /*!< [in] Sink context */ 156 const struct isoal_sink *sink_ctx, 157 /*!< [in] Filled valid SDU to be pushed */ 158 const struct isoal_sdu_produced *valid_sdu 159 ); 160 161 /** 162 * @brief Callback: Write a number of bytes to SDU buffer 163 */ 164 typedef isoal_status_t (*isoal_sink_sdu_write_cb)( 165 /*!< [in] Destination buffer */ 166 void *dbuf, 167 /*!< [in] Source data */ 168 const uint8_t *pdu_payload, 169 /*!< [in] Number of bytes to be copied */ 170 const size_t consume_len 171 ); 172 173 174 struct isoal_sink_config { 175 enum { 176 ISOAL_MODE_CIS, 177 ISOAL_MODE_BIS 178 } mode; 179 /* TODO add SDU and PDU max length etc. */ 180 }; 181 182 183 struct isoal_sink { 184 /* Session-constant */ 185 struct { 186 isoal_sink_sdu_alloc_cb sdu_alloc; 187 isoal_sink_sdu_emit_cb sdu_emit; 188 isoal_sink_sdu_write_cb sdu_write; 189 struct isoal_sink_config param; 190 isoal_sdu_cnt_t seqn; 191 uint16_t handle; 192 uint8_t pdus_per_sdu; 193 } session; 194 195 /* State for SDU production */ 196 struct { 197 /* Permit atomic enable/disable of SDU production */ 198 volatile isoal_production_mode_t mode; 199 /* We are constructing an SDU from {<1 or =1 or >1} PDUs */ 200 struct isoal_sdu_produced sdu; 201 /* Bookkeeping */ 202 isoal_pdu_cnt_t prev_pdu_id : 39; 203 enum { 204 ISOAL_START, 205 ISOAL_CONTINUE, 206 ISOAL_ERR_SPOOL 207 } fsm; 208 uint8_t pdu_cnt; 209 uint8_t sdu_state; 210 isoal_sdu_len_t sdu_written; 211 isoal_sdu_len_t sdu_available; 212 isoal_sdu_status_t sdu_status; 213 } sdu_production; 214 }; 215 216 217 isoal_status_t isoal_init(void); 218 219 isoal_status_t isoal_reset(void); 220 221 isoal_status_t isoal_sink_create(isoal_sink_handle_t *hdl, 222 uint16_t handle, 223 uint8_t burst_number, 224 uint32_t sdu_interval, 225 uint16_t iso_interval, 226 isoal_sink_sdu_alloc_cb sdu_alloc, 227 isoal_sink_sdu_emit_cb sdu_emit, 228 isoal_sink_sdu_write_cb sdu_write); 229 230 struct isoal_sink_config *isoal_get_sink_param_ref(isoal_sink_handle_t hdl); 231 232 void isoal_sink_enable(isoal_sink_handle_t hdl); 233 234 void isoal_sink_disable(isoal_sink_handle_t hdl); 235 236 void isoal_sink_destroy(isoal_sink_handle_t hdl); 237 238 isoal_status_t isoal_rx_pdu_recombine(isoal_sink_handle_t sink_hdl, 239 const struct isoal_pdu_rx *pdu_meta); 240 241 /* SDU Call backs for HCI interface */ 242 isoal_status_t sink_sdu_alloc_hci(const struct isoal_sink *sink_ctx, 243 const struct isoal_pdu_rx *valid_pdu, 244 struct isoal_sdu_buffer *sdu_buffer); 245 isoal_status_t sink_sdu_emit_hci(const struct isoal_sink *sink_ctx, 246 const struct isoal_sdu_produced *valid_sdu); 247 isoal_status_t sink_sdu_write_hci(void *dbuf, 248 const uint8_t *pdu_payload, 249 const size_t consume_len); 250