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] Number of bytes already written to this SDU */ 246 const size_t sdu_written, 247 /*!< [in] Source data */ 248 const uint8_t *pdu_payload, 249 /*!< [in] Number of bytes to be copied */ 250 const size_t consume_len 251 ); 252 253 struct isoal_sink_session { 254 isoal_sink_sdu_alloc_cb sdu_alloc; 255 isoal_sink_sdu_emit_cb sdu_emit; 256 isoal_sink_sdu_write_cb sdu_write; 257 isoal_sdu_cnt_t sn; 258 uint16_t handle; 259 uint16_t iso_interval; 260 uint8_t pdus_per_sdu; 261 uint8_t framed; 262 uint8_t burst_number; 263 uint32_t sdu_interval; 264 uint32_t sdu_sync_const; 265 }; 266 267 struct isoal_sdu_production { 268 #if defined(ISOAL_BUFFER_RX_SDUS_ENABLE) 269 /* Buffered SDUs */ 270 struct isoal_emit_sdu_queue sdu_list; 271 #endif 272 /* Permit atomic enable/disable of SDU production */ 273 volatile isoal_production_mode_t mode; 274 /* We are constructing an SDU from {<1 or =1 or >1} PDUs */ 275 struct isoal_sdu_produced sdu; 276 /* Bookkeeping */ 277 isoal_pdu_cnt_t prev_pdu_id : 39; 278 /* Assumes that isoal_pdu_cnt_t is a uint64_t bit field */ 279 uint64_t prev_pdu_is_end:1; 280 uint64_t prev_pdu_is_padding:1; 281 /* Indicates that only padding PDUs have been received for this SDU */ 282 uint64_t only_padding:1; 283 uint64_t sdu_allocated:1; 284 uint64_t initialized:1; 285 enum { 286 ISOAL_START, 287 ISOAL_CONTINUE, 288 ISOAL_ERR_SPOOL 289 } fsm; 290 uint8_t pdu_cnt; 291 uint8_t sdu_state; 292 isoal_sdu_len_t sdu_written; 293 isoal_sdu_len_t sdu_available; 294 isoal_sdu_status_t sdu_status; 295 }; 296 297 struct isoal_sink { 298 /* Session-constant */ 299 struct isoal_sink_session session; 300 301 /* State for SDU production */ 302 struct isoal_sdu_production sdu_production; 303 }; 304 305 /* Forward declaration */ 306 struct isoal_source; 307 308 /** 309 * @brief Callback: Request memory for a new ISO PDU buffer 310 * 311 * Proprietary ISO sub systems may have 312 * specific requirements or opinions on where to locate ISO PDUs; some 313 * memories may be faster, may be dynamically mapped in, etc. 314 * 315 * @return ISOAL_STATUS_ERR_ALLOC if size_request could not be fulfilled, otherwise 316 * ISOAL_STATUS_OK. 317 */ 318 typedef isoal_status_t (*isoal_source_pdu_alloc_cb)( 319 /*!< [out] Struct is modified. Must not be NULL */ 320 struct isoal_pdu_buffer *pdu_buffer 321 ); 322 323 /** 324 * @brief Callback: Release an ISO PDU 325 */ 326 typedef isoal_status_t (*isoal_source_pdu_release_cb)( 327 /*!< [in] PDU to be released */ 328 struct node_tx_iso *node_tx, 329 /*!< [in] CIS/BIS handle */ 330 const uint16_t handle, 331 /*!< [in] Cause of release. ISOAL_STATUS_OK means PDU was enqueued towards 332 * LLL and sent or flushed, and may need further handling before 333 * memory is released, e.g. forwarded to HCI thread for complete- 334 * counting. Any other status indicates cause of error during SDU 335 * fragmentation/segmentation, in which case the PDU will not be 336 * produced. 337 */ 338 const isoal_status_t status 339 ); 340 341 /** 342 * @brief Callback: Write a number of bytes to PDU buffer 343 */ 344 typedef isoal_status_t (*isoal_source_pdu_write_cb)( 345 /*!< [out] PDU under production */ 346 struct isoal_pdu_buffer *pdu_buffer, 347 /*!< [in] Offset within PDU buffer */ 348 const size_t offset, 349 /*!< [in] Source data */ 350 const uint8_t *sdu_payload, 351 /*!< [in] Number of bytes to be copied */ 352 const size_t consume_len 353 ); 354 355 /** 356 * @brief Callback: Enqueue an ISO PDU 357 */ 358 typedef isoal_status_t (*isoal_source_pdu_emit_cb)( 359 /*!< [in] PDU to be enqueued */ 360 struct node_tx_iso *node_tx, 361 /*!< [in] CIS/BIS handle */ 362 const uint16_t handle 363 ); 364 365 struct isoal_source_session { 366 isoal_source_pdu_alloc_cb pdu_alloc; 367 isoal_source_pdu_write_cb pdu_write; 368 isoal_source_pdu_emit_cb pdu_emit; 369 isoal_source_pdu_release_cb pdu_release; 370 371 isoal_sdu_cnt_t sn; 372 uint16_t last_input_sn; 373 uint32_t last_input_time_stamp; 374 uint32_t tx_time_stamp; 375 uint32_t tx_time_offset; 376 uint32_t sdu_interval; 377 uint16_t handle; 378 uint16_t iso_interval; 379 uint8_t framed; 380 uint8_t burst_number; 381 uint8_t pdus_per_sdu; 382 uint8_t max_pdu_size; 383 }; 384 385 struct isoal_pdu_production { 386 /* Permit atomic enable/disable of PDU production */ 387 volatile isoal_production_mode_t mode; 388 /* We are constructing a PDU from {<1 or =1 or >1} SDUs */ 389 struct isoal_pdu_produced pdu; 390 uint8_t pdu_state; 391 /* PDUs produced for current SDU */ 392 uint8_t pdu_cnt; 393 uint64_t payload_number:39; 394 uint64_t seg_hdr_sc:1; 395 uint64_t seg_hdr_length:8; 396 uint64_t sdu_fragments:8; 397 uint64_t initialized:1; 398 uint64_t pdu_allocated:1; 399 isoal_pdu_len_t pdu_written; 400 isoal_pdu_len_t pdu_available; 401 /* Location (byte index) of last segmentation header */ 402 isoal_pdu_len_t last_seg_hdr_loc; 403 }; 404 405 struct isoal_source { 406 /* Session-constant */ 407 struct isoal_source_session session; 408 409 /* State for PDU production */ 410 struct isoal_pdu_production pdu_production; 411 412 /* Context Control */ 413 uint64_t timeout_event_count:39; 414 uint64_t timeout_trigger:1; 415 uint64_t context_active:1; 416 }; 417 418 uint32_t isoal_get_wrapped_time_us(uint32_t time_now_us, int32_t time_diff_us); 419 420 isoal_status_t isoal_init(void); 421 422 isoal_status_t isoal_reset(void); 423 424 isoal_status_t isoal_sink_create(uint16_t handle, 425 uint8_t role, 426 uint8_t framed, 427 uint8_t burst_number, 428 uint8_t flush_timeout, 429 uint32_t sdu_interval, 430 uint16_t iso_interval, 431 uint32_t stream_sync_delay, 432 uint32_t group_sync_delay, 433 isoal_sink_sdu_alloc_cb sdu_alloc, 434 isoal_sink_sdu_emit_cb sdu_emit, 435 isoal_sink_sdu_write_cb sdu_write, 436 isoal_sink_handle_t *hdl); 437 438 void isoal_sink_enable(isoal_sink_handle_t hdl); 439 440 void isoal_sink_disable(isoal_sink_handle_t hdl); 441 442 void isoal_sink_destroy(isoal_sink_handle_t hdl); 443 444 isoal_status_t isoal_rx_pdu_recombine(isoal_sink_handle_t sink_hdl, 445 const struct isoal_pdu_rx *pdu_meta); 446 447 /* SDU Call backs for HCI interface */ 448 isoal_status_t sink_sdu_alloc_hci(const struct isoal_sink *sink_ctx, 449 const struct isoal_pdu_rx *valid_pdu, 450 struct isoal_sdu_buffer *sdu_buffer); 451 isoal_status_t sink_sdu_emit_hci(const struct isoal_sink *sink_ctx, 452 const struct isoal_emitted_sdu_frag *sdu_frag, 453 const struct isoal_emitted_sdu *sdu); 454 isoal_status_t sink_sdu_write_hci(void *dbuf, 455 const size_t sdu_written, 456 const uint8_t *pdu_payload, 457 const size_t consume_len); 458 459 isoal_status_t isoal_source_create(uint16_t handle, 460 uint8_t role, 461 uint8_t framed, 462 uint8_t burst_number, 463 uint8_t flush_timeout, 464 uint8_t max_octets, 465 uint32_t sdu_interval, 466 uint16_t iso_interval, 467 uint32_t stream_sync_delay, 468 uint32_t group_sync_delay, 469 isoal_source_pdu_alloc_cb pdu_alloc, 470 isoal_source_pdu_write_cb pdu_write, 471 isoal_source_pdu_emit_cb pdu_emit, 472 isoal_source_pdu_release_cb pdu_release, 473 isoal_source_handle_t *hdl); 474 475 void isoal_source_enable(isoal_source_handle_t hdl); 476 477 void isoal_source_disable(isoal_source_handle_t hdl); 478 479 void isoal_source_destroy(isoal_source_handle_t hdl); 480 481 isoal_status_t isoal_tx_sdu_fragment(isoal_source_handle_t source_hdl, 482 struct isoal_sdu_tx *tx_sdu); 483 484 uint16_t isoal_tx_unframed_get_next_payload_number(isoal_source_handle_t source_hdl, 485 const struct isoal_sdu_tx *tx_sdu, 486 uint64_t *payload_number); 487 488 void isoal_tx_pdu_release(isoal_source_handle_t source_hdl, 489 struct node_tx_iso *node_tx); 490 491 isoal_status_t isoal_tx_get_sync_info(isoal_source_handle_t source_hdl, 492 uint16_t *seq, 493 uint32_t *timestamp, 494 uint32_t *offset); 495 496 void isoal_tx_event_prepare(isoal_source_handle_t source_hdl, 497 uint64_t event_number); 498