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