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