1 /* 2 * Copyright (c) 2021 Demant 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #if defined(CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS) && (CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS > 0) 8 #define ISOAL_BUFFER_RX_SDUS_ENABLE 9 #endif /* CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS > 0 */ 10 11 12 /** Function return error codes */ 13 typedef uint8_t isoal_status_t; 14 #define ISOAL_STATUS_OK ((isoal_status_t) 0x00) /* No error */ 15 #define ISOAL_STATUS_ERR_SINK_ALLOC ((isoal_status_t) 0x01) /* Sink pool full */ 16 #define ISOAL_STATUS_ERR_SOURCE_ALLOC ((isoal_status_t) 0x02) /* Source pool full */ 17 #define ISOAL_STATUS_ERR_SDU_ALLOC ((isoal_status_t) 0x04) /* SDU allocation */ 18 #define ISOAL_STATUS_ERR_SDU_EMIT ((isoal_status_t) 0x08) /* SDU emission */ 19 #define ISOAL_STATUS_ERR_PDU_ALLOC ((isoal_status_t) 0x10) /* PDU allocation */ 20 #define ISOAL_STATUS_ERR_PDU_EMIT ((isoal_status_t) 0x20) /* PDU emission */ 21 #define ISOAL_STATUS_ERR_UNSPECIFIED ((isoal_status_t) 0x80) /* Unspecified error */ 22 23 #define ISOAL_ROLE_CENTRAL (BT_CONN_ROLE_CENTRAL) 24 #define ISOAL_ROLE_PERIPHERAL (BT_CONN_ROLE_PERIPHERAL) 25 #define ISOAL_ROLE_BROADCAST_SOURCE (BT_CONN_ROLE_PERIPHERAL + 1U) 26 #define ISOAL_ROLE_BROADCAST_SINK (BT_CONN_ROLE_PERIPHERAL + 2U) 27 28 /** Handle to a registered ISO Sub-System sink */ 29 typedef uint8_t isoal_sink_handle_t; 30 31 /** Handle to a registered ISO Sub-System source */ 32 typedef uint8_t isoal_source_handle_t; 33 34 /** Byte length of an ISO SDU */ 35 typedef uint16_t isoal_sdu_len_t; 36 37 /** Byte length of an ISO PDU */ 38 typedef uint8_t isoal_pdu_len_t; 39 40 /** Count (ID number) of an ISO SDU */ 41 typedef uint16_t isoal_sdu_cnt_t; 42 43 /** Count (ID number) of an ISO PDU */ 44 typedef uint64_t isoal_pdu_cnt_t; 45 46 /** Ticks. Used for timestamp */ 47 typedef uint32_t isoal_time_t; 48 49 /** SDU status codes */ 50 typedef uint8_t isoal_sdu_status_t; 51 #define ISOAL_SDU_STATUS_VALID ((isoal_sdu_status_t) 0x00) 52 #define ISOAL_SDU_STATUS_ERRORS ((isoal_sdu_status_t) 0x01) 53 #define ISOAL_SDU_STATUS_LOST_DATA ((isoal_sdu_status_t) 0x02) 54 55 /** PDU status codes */ 56 typedef uint8_t isoal_pdu_status_t; 57 #define ISOAL_PDU_STATUS_VALID ((isoal_pdu_status_t) 0x00) 58 #define ISOAL_PDU_STATUS_ERRORS ((isoal_pdu_status_t) 0x01) 59 #define ISOAL_PDU_STATUS_LOST_DATA ((isoal_pdu_status_t) 0x02) 60 61 /** Production mode */ 62 typedef uint8_t isoal_production_mode_t; 63 #define ISOAL_PRODUCTION_MODE_DISABLED ((isoal_production_mode_t) 0x00) 64 #define ISOAL_PRODUCTION_MODE_ENABLED ((isoal_production_mode_t) 0x01) 65 66 67 enum isoal_mode { 68 ISOAL_MODE_CIS, 69 ISOAL_MODE_BIS 70 }; 71 72 /** 73 * @brief ISO frame SDU buffer - typically an Audio frame buffer 74 * 75 * This provides the underlying vehicle of ISO SDU interchange through the 76 * ISO socket, the contents of which is generally an array of encoded bytes. 77 * Access and life time of this should be limited to ISO and the ISO socket. 78 * We assume no byte-fractional code words. 79 * 80 * Decoding code words to samples is the responsibility of the ISO sub system. 81 */ 82 struct isoal_sdu_buffer { 83 /** Code word buffer 84 * Type, location and alignment decided by ISO sub system 85 */ 86 void *dbuf; 87 /** Number of bytes accessible behind the dbuf pointer */ 88 isoal_sdu_len_t size; 89 }; 90 91 92 /** 93 * @brief ISO frame PDU buffer 94 */ 95 struct isoal_pdu_buffer { 96 /** Additional handle for the provided pdu */ 97 void *handle; 98 /** PDU contents */ 99 struct pdu_iso *pdu; 100 /** Maximum size of the data buffer allocated for the payload in the PDU. 101 * Should be at least Max_PDU_C_To_P / Max_PDU_P_To_C depending on 102 * the role. 103 */ 104 isoal_pdu_len_t size; 105 }; 106 107 108 /** @brief Produced ISO SDU frame with associated meta data */ 109 struct isoal_sdu_produced { 110 /** Status of contents, if valid or SDU was lost. 111 * This maps directly to the HCI ISO Data packet Packet_Status_Flag. 112 * BT Core V5.3 : Vol 4 HCI I/F : Part G HCI Func. Spec.: 113 * 5.4.5 HCI ISO Data packets : Table 5.2 : 114 * Packet_Status_Flag (in packets sent by the Controller) 115 */ 116 isoal_sdu_status_t status; 117 /** Regardless of status, we always have timing */ 118 isoal_time_t timestamp; 119 /** Sequence number of SDU */ 120 isoal_sdu_cnt_t sn; 121 /** Contents and length can only be trusted if status is valid */ 122 struct isoal_sdu_buffer contents; 123 /** Optional context to be carried from PDU at alloc-time */ 124 void *ctx; 125 }; 126 127 /** @brief Produced ISO SDU fragment and status information to be emitted */ 128 struct isoal_emitted_sdu_frag { 129 /** Produced SDU to be emitted */ 130 struct isoal_sdu_produced sdu; 131 /** SDU fragment Packet Boundary flags */ 132 uint8_t sdu_state; 133 /** Size of the SDU fragment */ 134 isoal_sdu_len_t sdu_frag_size; 135 }; 136 137 /** @brief Produced ISO SDU and required status information to be emitted */ 138 struct isoal_emitted_sdu { 139 /** Size of the SDU across all fragments */ 140 isoal_sdu_len_t total_sdu_size; 141 /** Status of contents, if valid or SDU was lost. 142 * This maps directly to the HCI ISO Data packet Packet_Status_Flag. 143 * BT Core V5.3 : Vol 4 HCI I/F : Part G HCI Func. Spec.: 144 * 5.4.5 HCI ISO Data packets : Table 5.2 : 145 * Packet_Status_Flag (in packets sent by the Controller) 146 */ 147 isoal_sdu_status_t collated_status; 148 }; 149 150 #if defined(ISOAL_BUFFER_RX_SDUS_ENABLE) 151 struct isoal_emit_sdu_queue { 152 struct isoal_emitted_sdu_frag list[CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS]; 153 uint16_t next_write_indx; 154 }; 155 #endif /* ISOAL_BUFFER_RX_SDUS_ENABLE */ 156 157 /** @brief Produced ISO PDU encapsulation */ 158 struct isoal_pdu_produced { 159 /** Contents information provided at PDU allocation */ 160 struct isoal_pdu_buffer contents; 161 }; 162 163 164 /** @brief Received ISO PDU with associated meta data */ 165 struct isoal_pdu_rx { 166 /** Meta */ 167 struct node_rx_iso_meta *meta; 168 /** PDU contents and length can only be trusted if status is valid */ 169 struct pdu_iso *pdu; 170 }; 171 172 /** @brief Received ISO SDU with associated meta data */ 173 struct isoal_sdu_tx { 174 /** Code word buffer 175 * Type, location and alignment decided by ISO sub system 176 */ 177 void *dbuf; 178 /** Number of bytes accessible behind the dbuf pointer */ 179 isoal_sdu_len_t size; 180 /** SDU packet boundary flags from HCI indicating the fragment type 181 * can be directly assigned to the SDU state 182 */ 183 uint8_t sdu_state; 184 /** Packet sequence number from HCI ISO Data Header (ISO Data Load 185 * Field) 186 */ 187 uint16_t packet_sn; 188 /** ISO SDU length from HCI ISO Data Header (ISO Data Load Field) */ 189 uint16_t iso_sdu_length; 190 /** Time stamp from HCI or vendor specific path (us) */ 191 uint32_t time_stamp; 192 /** Capture time stamp from controller (us) */ 193 uint32_t cntr_time_stamp; 194 /** CIG Reference of target event (us, compensated for drift) */ 195 uint32_t grp_ref_point; 196 /** Target Event of SDU */ 197 uint64_t target_event:39; 198 }; 199 200 201 202 /* Forward declaration */ 203 struct isoal_sink; 204 struct node_tx_iso; 205 206 /** 207 * @brief Callback: Request memory for a new ISO SDU buffer 208 * 209 * Proprietary ISO sub systems may have 210 * specific requirements or opinions on where to locate ISO SDUs; some 211 * memories may be faster, may be dynamically mapped in, etc. 212 * 213 * @return ISOAL_STATUS_ERR_ALLOC if size_request could not be fulfilled, otherwise 214 * ISOAL_STATUS_OK. 215 */ 216 typedef isoal_status_t (*isoal_sink_sdu_alloc_cb)( 217 /*!< [in] Sink context */ 218 const struct isoal_sink *sink_ctx, 219 /*!< [in] Received PDU */ 220 const struct isoal_pdu_rx *valid_pdu, 221 /*!< [out] Struct is modified. Must not be NULL */ 222 struct isoal_sdu_buffer *sdu_buffer 223 ); 224 225 /** 226 * @brief Callback: Push an ISO SDU into an ISO sink 227 * 228 * Call also handing back buffer ownership 229 */ 230 typedef isoal_status_t (*isoal_sink_sdu_emit_cb)( 231 /*!< [in] Sink context */ 232 const struct isoal_sink *sink_ctx, 233 /*!< [in] Emitted SDU fragment and status information */ 234 const struct isoal_emitted_sdu_frag *sdu_frag, 235 /*!< [in] Emitted SDU status information */ 236 const struct isoal_emitted_sdu *sdu 237 ); 238 239 /** 240 * @brief Callback: Write a number of bytes to SDU buffer 241 */ 242 typedef isoal_status_t (*isoal_sink_sdu_write_cb)( 243 /*!< [in] Destination buffer */ 244 void *dbuf, 245 /*!< [in] Source data */ 246 const uint8_t *pdu_payload, 247 /*!< [in] Number of bytes to be copied */ 248 const size_t consume_len 249 ); 250 251 struct isoal_sink_session { 252 isoal_sink_sdu_alloc_cb sdu_alloc; 253 isoal_sink_sdu_emit_cb sdu_emit; 254 isoal_sink_sdu_write_cb sdu_write; 255 isoal_sdu_cnt_t sn; 256 uint16_t handle; 257 uint16_t iso_interval; 258 uint8_t pdus_per_sdu; 259 uint8_t framed; 260 uint8_t burst_number; 261 uint32_t sdu_interval; 262 uint32_t sdu_sync_const; 263 }; 264 265 struct isoal_sdu_production { 266 #if defined(ISOAL_BUFFER_RX_SDUS_ENABLE) 267 /* Buffered SDUs */ 268 struct isoal_emit_sdu_queue sdu_list; 269 #endif 270 /* Permit atomic enable/disable of SDU production */ 271 volatile isoal_production_mode_t mode; 272 /* We are constructing an SDU from {<1 or =1 or >1} PDUs */ 273 struct isoal_sdu_produced sdu; 274 /* Bookkeeping */ 275 isoal_pdu_cnt_t prev_pdu_id : 39; 276 /* Assumes that isoal_pdu_cnt_t is a uint64_t bit field */ 277 uint64_t prev_pdu_is_end:1; 278 uint64_t prev_pdu_is_padding:1; 279 /* Indicates that only padding PDUs have been received for this SDU */ 280 uint64_t only_padding:1; 281 uint64_t sdu_allocated:1; 282 uint64_t initialized:1; 283 enum { 284 ISOAL_START, 285 ISOAL_CONTINUE, 286 ISOAL_ERR_SPOOL 287 } fsm; 288 uint8_t pdu_cnt; 289 uint8_t sdu_state; 290 isoal_sdu_len_t sdu_written; 291 isoal_sdu_len_t sdu_available; 292 isoal_sdu_status_t sdu_status; 293 }; 294 295 struct isoal_sink { 296 /* Session-constant */ 297 struct isoal_sink_session session; 298 299 /* State for SDU production */ 300 struct isoal_sdu_production sdu_production; 301 }; 302 303 /* Forward declaration */ 304 struct isoal_source; 305 306 /** 307 * @brief Callback: Request memory for a new ISO PDU buffer 308 * 309 * Proprietary ISO sub systems may have 310 * specific requirements or opinions on where to locate ISO PDUs; some 311 * memories may be faster, may be dynamically mapped in, etc. 312 * 313 * @return ISOAL_STATUS_ERR_ALLOC if size_request could not be fulfilled, otherwise 314 * ISOAL_STATUS_OK. 315 */ 316 typedef isoal_status_t (*isoal_source_pdu_alloc_cb)( 317 /*!< [out] Struct is modified. Must not be NULL */ 318 struct isoal_pdu_buffer *pdu_buffer 319 ); 320 321 /** 322 * @brief Callback: Release an ISO PDU 323 */ 324 typedef isoal_status_t (*isoal_source_pdu_release_cb)( 325 /*!< [in] PDU to be released */ 326 struct node_tx_iso *node_tx, 327 /*!< [in] CIS/BIS handle */ 328 const uint16_t handle, 329 /*!< [in] Cause of release. ISOAL_STATUS_OK means PDU was enqueued towards 330 * LLL and sent or flushed, and may need further handling before 331 * memory is released, e.g. forwarded to HCI thread for complete- 332 * counting. Any other status indicates cause of error during SDU 333 * fragmentation/segmentation, in which case the PDU will not be 334 * produced. 335 */ 336 const isoal_status_t status 337 ); 338 339 /** 340 * @brief Callback: Write a number of bytes to PDU buffer 341 */ 342 typedef isoal_status_t (*isoal_source_pdu_write_cb)( 343 /*!< [out] PDU under production */ 344 struct isoal_pdu_buffer *pdu_buffer, 345 /*!< [in] Offset within PDU buffer */ 346 const size_t offset, 347 /*!< [in] Source data */ 348 const uint8_t *sdu_payload, 349 /*!< [in] Number of bytes to be copied */ 350 const size_t consume_len 351 ); 352 353 /** 354 * @brief Callback: Enqueue an ISO PDU 355 */ 356 typedef isoal_status_t (*isoal_source_pdu_emit_cb)( 357 /*!< [in] PDU to be enqueued */ 358 struct node_tx_iso *node_tx, 359 /*!< [in] CIS/BIS handle */ 360 const uint16_t handle 361 ); 362 363 struct isoal_source_session { 364 isoal_source_pdu_alloc_cb pdu_alloc; 365 isoal_source_pdu_write_cb pdu_write; 366 isoal_source_pdu_emit_cb pdu_emit; 367 isoal_source_pdu_release_cb pdu_release; 368 369 isoal_sdu_cnt_t sn; 370 uint16_t last_input_sn; 371 uint32_t last_input_time_stamp; 372 uint32_t tx_time_stamp; 373 uint32_t tx_time_offset; 374 uint32_t sdu_interval; 375 uint16_t handle; 376 uint16_t iso_interval; 377 uint8_t framed; 378 uint8_t burst_number; 379 uint8_t pdus_per_sdu; 380 uint8_t max_pdu_size; 381 }; 382 383 struct isoal_pdu_production { 384 /* Permit atomic enable/disable of PDU production */ 385 volatile isoal_production_mode_t mode; 386 /* We are constructing a PDU from {<1 or =1 or >1} SDUs */ 387 struct isoal_pdu_produced pdu; 388 uint8_t pdu_state; 389 /* PDUs produced for current SDU */ 390 uint8_t pdu_cnt; 391 uint64_t payload_number:39; 392 uint64_t seg_hdr_sc:1; 393 uint64_t seg_hdr_length:8; 394 uint64_t sdu_fragments:8; 395 uint64_t initialized:1; 396 uint64_t pdu_allocated:1; 397 isoal_pdu_len_t pdu_written; 398 isoal_pdu_len_t pdu_available; 399 /* Location (byte index) of last segmentation header */ 400 isoal_pdu_len_t last_seg_hdr_loc; 401 }; 402 403 struct isoal_source { 404 /* Session-constant */ 405 struct isoal_source_session session; 406 407 /* State for PDU production */ 408 struct isoal_pdu_production pdu_production; 409 410 /* Context Control */ 411 uint64_t timeout_event_count:39; 412 uint64_t timeout_trigger:1; 413 uint64_t context_active:1; 414 }; 415 416 uint32_t isoal_get_wrapped_time_us(uint32_t time_now_us, int32_t time_diff_us); 417 418 isoal_status_t isoal_init(void); 419 420 isoal_status_t isoal_reset(void); 421 422 isoal_status_t isoal_sink_create(uint16_t handle, 423 uint8_t role, 424 uint8_t framed, 425 uint8_t burst_number, 426 uint8_t flush_timeout, 427 uint32_t sdu_interval, 428 uint16_t iso_interval, 429 uint32_t stream_sync_delay, 430 uint32_t group_sync_delay, 431 isoal_sink_sdu_alloc_cb sdu_alloc, 432 isoal_sink_sdu_emit_cb sdu_emit, 433 isoal_sink_sdu_write_cb sdu_write, 434 isoal_sink_handle_t *hdl); 435 436 void isoal_sink_enable(isoal_sink_handle_t hdl); 437 438 void isoal_sink_disable(isoal_sink_handle_t hdl); 439 440 void isoal_sink_destroy(isoal_sink_handle_t hdl); 441 442 isoal_status_t isoal_rx_pdu_recombine(isoal_sink_handle_t sink_hdl, 443 const struct isoal_pdu_rx *pdu_meta); 444 445 /* SDU Call backs for HCI interface */ 446 isoal_status_t sink_sdu_alloc_hci(const struct isoal_sink *sink_ctx, 447 const struct isoal_pdu_rx *valid_pdu, 448 struct isoal_sdu_buffer *sdu_buffer); 449 isoal_status_t sink_sdu_emit_hci(const struct isoal_sink *sink_ctx, 450 const struct isoal_emitted_sdu_frag *sdu_frag, 451 const struct isoal_emitted_sdu *sdu); 452 isoal_status_t sink_sdu_write_hci(void *dbuf, 453 const uint8_t *pdu_payload, 454 const size_t consume_len); 455 456 isoal_status_t isoal_source_create(uint16_t handle, 457 uint8_t role, 458 uint8_t framed, 459 uint8_t burst_number, 460 uint8_t flush_timeout, 461 uint8_t max_octets, 462 uint32_t sdu_interval, 463 uint16_t iso_interval, 464 uint32_t stream_sync_delay, 465 uint32_t group_sync_delay, 466 isoal_source_pdu_alloc_cb pdu_alloc, 467 isoal_source_pdu_write_cb pdu_write, 468 isoal_source_pdu_emit_cb pdu_emit, 469 isoal_source_pdu_release_cb pdu_release, 470 isoal_source_handle_t *hdl); 471 472 void isoal_source_enable(isoal_source_handle_t hdl); 473 474 void isoal_source_disable(isoal_source_handle_t hdl); 475 476 void isoal_source_destroy(isoal_source_handle_t hdl); 477 478 isoal_status_t isoal_tx_sdu_fragment(isoal_source_handle_t source_hdl, 479 struct isoal_sdu_tx *tx_sdu); 480 481 uint16_t isoal_tx_unframed_get_next_payload_number(isoal_source_handle_t source_hdl, 482 const struct isoal_sdu_tx *tx_sdu, 483 uint64_t *payload_number); 484 485 void isoal_tx_pdu_release(isoal_source_handle_t source_hdl, 486 struct node_tx_iso *node_tx); 487 488 isoal_status_t isoal_tx_get_sync_info(isoal_source_handle_t source_hdl, 489 uint16_t *seq, 490 uint32_t *timestamp, 491 uint32_t *offset); 492 493 void isoal_tx_event_prepare(isoal_source_handle_t source_hdl, 494 uint64_t event_number); 495