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