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