1 /*
2  * Copyright (c) 2020 Demant
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  *  Run this test from zephyr directory as:
7  *
8  *     ./scripts/twister --coverage -p native_posix -v -T tests/bluetooth/ctrl_isoal/
9  *
10  */
11 
12 #include <string.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 
16 #include <zephyr/types.h>
17 #include <zephyr/ztest.h>
18 #include <zephyr/ztest_error_hook.h>
19 
20 #include <zephyr/toolchain.h>
21 #include <zephyr/sys/util.h>
22 
23 #include <zephyr/kernel.h>
24 
25 #include <zephyr/bluetooth/bluetooth.h>
26 
27 #include "util/memq.h"
28 
29 #include "pdu_df.h"
30 #include "lll/pdu_vendor.h"
31 #include "pdu.h"
32 
33 #include "ll.h"
34 #include "lll.h"
35 #include "lll_conn_iso.h"
36 #include "lll_iso_tx.h"
37 #include "isoal.h"
38 
39 #include "isoal_test_common.h"
40 #include "isoal_test_debug.h"
41 
42 
43 /**
44  * Intializes a RX PDU buffer
45  * @param[in] buf Pointer to buffer structure
46  */
isoal_test_init_rx_pdu_buffer(struct rx_pdu_meta_buffer * buf)47 void isoal_test_init_rx_pdu_buffer(struct rx_pdu_meta_buffer *buf)
48 {
49 	memset(buf, 0, sizeof(struct rx_pdu_meta_buffer));
50 	buf->pdu_meta.meta = &buf->meta;
51 	buf->pdu_meta.pdu = (struct pdu_iso *) &buf->pdu[0];
52 }
53 
54 /**
55  * Initializes a RX SDU buffer
56  * @param[in] buf Pointer to buffer structure
57  */
isoal_test_init_rx_sdu_buffer(struct rx_sdu_frag_buffer * buf)58 void isoal_test_init_rx_sdu_buffer(struct rx_sdu_frag_buffer *buf)
59 {
60 	memset(buf, 0, sizeof(struct rx_sdu_frag_buffer));
61 }
62 
63 /**
64  * Creates an unframed PDU fragment according to provided parameters
65  * @param[in]  llid           LLID as Start / Continue or Complete / End
66  * @param[in]  dataptr        Test data to fill PDU payload
67  * @param[in]  length         Length of PDU payload
68  * @param[in]  payload_number Payload number (Meta Information)
69  * @param[in]  timestamp      PDU reception Time (Meta Information)
70  * @param[in]  status         PDU data validity
71  * @param[out] pdu_meta       PDU buffer including meta structure
72  */
isoal_test_create_unframed_pdu(uint8_t llid,uint8_t * dataptr,uint8_t length,uint64_t payload_number,uint32_t timestamp,uint8_t status,struct isoal_pdu_rx * pdu_meta)73 void isoal_test_create_unframed_pdu(uint8_t llid,
74 				uint8_t *dataptr,
75 				uint8_t length,
76 				uint64_t payload_number,
77 				uint32_t timestamp,
78 				uint8_t  status,
79 				struct isoal_pdu_rx *pdu_meta)
80 {
81 	zassert_not_null(pdu_meta, "");
82 	zassert_not_null(pdu_meta->meta, "");
83 	zassert_not_null(pdu_meta->pdu, "");
84 
85 	memset(pdu_meta->meta, 0, sizeof(*pdu_meta->meta));
86 	memset(pdu_meta->pdu, 0, sizeof(*pdu_meta->pdu));
87 
88 	pdu_meta->meta->payload_number = payload_number;
89 	pdu_meta->meta->timestamp = timestamp;
90 	pdu_meta->meta->status = status;
91 
92 	pdu_meta->pdu->ll_id = llid;
93 	pdu_meta->pdu->len = length;
94 	memcpy(pdu_meta->pdu->payload, dataptr, length);
95 
96 	isoal_test_debug_print_rx_pdu(pdu_meta);
97 }
98 
99 /**
100  * Insert a new segment in the given PDU
101  * @param[In]     sc          !Start / Continuation bit
102  * @param[In]     cmplt       Complete bit
103  * @param[In]     time_offset Time Offset (us)
104  * @param[In]     dataptr     Pointer to data to fill in segment
105  * @param[In]     length      Length of data
106  * @param[In/Out] pdu_meta    PDU structure including meta information
107  * @return                    PDU data location index
108  */
isoal_test_insert_segment(bool sc,bool cmplt,uint32_t time_offset,uint8_t * dataptr,uint8_t length,struct isoal_pdu_rx * pdu_meta)109 uint16_t isoal_test_insert_segment(bool sc, bool cmplt, uint32_t time_offset, uint8_t *dataptr,
110 				uint8_t length, struct isoal_pdu_rx *pdu_meta)
111 {
112 	struct pdu_iso_sdu_sh seg_hdr;
113 	uint16_t pdu_payload_size;
114 	uint8_t hdr_write_size;
115 	uint16_t pdu_data_loc;
116 
117 	pdu_payload_size = pdu_meta->pdu->len + length + PDU_ISO_SEG_HDR_SIZE +
118 			(sc ? 0 : PDU_ISO_SEG_TIMEOFFSET_SIZE);
119 	hdr_write_size = PDU_ISO_SEG_HDR_SIZE + (sc ? 0 : PDU_ISO_SEG_TIMEOFFSET_SIZE);
120 	memset(&seg_hdr, 0, sizeof(seg_hdr));
121 
122 	zassert_true(pdu_payload_size <= TEST_RX_PDU_PAYLOAD_MAX,
123 		"pdu_payload_size (%d)", pdu_payload_size);
124 
125 	seg_hdr.sc = sc;
126 	seg_hdr.cmplt = cmplt;
127 	seg_hdr.len = length + (sc ? 0 : PDU_ISO_SEG_TIMEOFFSET_SIZE);
128 
129 	if (!sc) {
130 		seg_hdr.timeoffset = time_offset;
131 	}
132 
133 	memcpy(&pdu_meta->pdu->payload[pdu_meta->pdu->len], &seg_hdr, hdr_write_size);
134 	pdu_meta->pdu->len += hdr_write_size;
135 
136 	memcpy(&pdu_meta->pdu->payload[pdu_meta->pdu->len], dataptr, length);
137 	pdu_data_loc = pdu_meta->pdu->len;
138 	pdu_meta->pdu->len += length;
139 
140 	isoal_test_debug_print_rx_pdu(pdu_meta);
141 
142 	return pdu_data_loc;
143 }
144 
145 /**
146  * Create and fill in base information for a framed PDU
147  * @param[In]     payload_number Payload number (Meta Information)
148  * @param[In]     timestamp      Adjusted RX time stamp (CIS anchorpoint)
149  * @param[In]     status         PDU error status
150  * @param[In/Out] pdu_meta       PDU structure including meta information
151  */
isoal_test_create_framed_pdu_base(uint64_t payload_number,uint32_t timestamp,uint8_t status,struct isoal_pdu_rx * pdu_meta)152 void isoal_test_create_framed_pdu_base(uint64_t payload_number, uint32_t timestamp, uint8_t  status,
153 					struct isoal_pdu_rx *pdu_meta)
154 {
155 	zassert_not_null(pdu_meta, "");
156 	zassert_not_null(pdu_meta->meta, "");
157 	zassert_not_null(pdu_meta->pdu, "");
158 
159 	memset(pdu_meta->meta, 0, sizeof(*pdu_meta->meta));
160 	memset(pdu_meta->pdu, 0, sizeof(*pdu_meta->pdu));
161 
162 	pdu_meta->meta->payload_number = payload_number;
163 	pdu_meta->meta->timestamp = timestamp;
164 	pdu_meta->meta->status = status;
165 
166 	pdu_meta->pdu->ll_id = PDU_BIS_LLID_FRAMED;
167 	pdu_meta->pdu->len = 0;
168 
169 	isoal_test_debug_print_rx_pdu(pdu_meta);
170 }
171 
172 /**
173  * Adds a single SDU framed segment to the given PDU
174  * @param[In]     dataptr     Pointer to data to fill in segment
175  * @param[In]     length      Length of data
176  * @param[In]     time_offset Time offset
177  * @param[In/Out] pdu_meta    PDU structure including meta information
178  * @return                    PDU data location index
179  */
isoal_test_add_framed_pdu_single(uint8_t * dataptr,uint8_t length,uint32_t time_offset,struct isoal_pdu_rx * pdu_meta)180 uint16_t isoal_test_add_framed_pdu_single(uint8_t *dataptr, uint8_t length, uint32_t time_offset,
181 					struct isoal_pdu_rx *pdu_meta)
182 {
183 	zassert_not_null(pdu_meta, "");
184 	zassert_not_null(pdu_meta->meta, "");
185 	zassert_not_null(pdu_meta->pdu, "");
186 
187 	return isoal_test_insert_segment(false, true, time_offset, dataptr, length, pdu_meta);
188 }
189 
190 /**
191  * Adds a starting SDU framed segment to the given PDU
192  * @param[In]     dataptr     Pointer to data to fill in segment
193  * @param[In]     length      Length of data
194  * @param[In]     time_offset Time offset
195  * @param[In/Out] pdu_meta    PDU structure including meta information
196  * @return                    PDU data location index
197  */
isoal_test_add_framed_pdu_start(uint8_t * dataptr,uint8_t length,uint32_t time_offset,struct isoal_pdu_rx * pdu_meta)198 uint16_t isoal_test_add_framed_pdu_start(uint8_t *dataptr, uint8_t length, uint32_t time_offset,
199 					struct isoal_pdu_rx *pdu_meta)
200 {
201 	zassert_not_null(pdu_meta, "");
202 	zassert_not_null(pdu_meta->meta, "");
203 	zassert_not_null(pdu_meta->pdu, "");
204 
205 	return isoal_test_insert_segment(false, false, time_offset, dataptr, length, pdu_meta);
206 }
207 
208 /**
209  * Adds a continuation SDU framed segment to the given PDU
210  * @param[In]     dataptr     Pointer to data to fill in segment
211  * @param[In]     length      Length of data
212  * @param[In/Out] pdu_meta    PDU structure including meta information
213  * @return                    PDU data location index
214  */
isoal_test_add_framed_pdu_cont(uint8_t * dataptr,uint8_t length,struct isoal_pdu_rx * pdu_meta)215 uint16_t isoal_test_add_framed_pdu_cont(uint8_t *dataptr,
216 					uint8_t length,
217 					struct isoal_pdu_rx *pdu_meta)
218 {
219 	zassert_not_null(pdu_meta, "");
220 	zassert_not_null(pdu_meta->meta, "");
221 	zassert_not_null(pdu_meta->pdu, "");
222 
223 	return isoal_test_insert_segment(true, false, 0, dataptr, length, pdu_meta);
224 }
225 
226 /**
227  * Adds an end SDU framed segment to the given PDU
228  * @param[In]     dataptr     Pointer to data to fill in segment
229  * @param[In]     length      Length of data
230  * @param[In/Out] pdu_meta    PDU structure including meta information
231  * @return                    PDU data location index
232  */
isoal_test_add_framed_pdu_end(uint8_t * dataptr,uint8_t length,struct isoal_pdu_rx * pdu_meta)233 uint16_t isoal_test_add_framed_pdu_end(uint8_t *dataptr,
234 				       uint8_t length,
235 				       struct isoal_pdu_rx *pdu_meta)
236 {
237 	zassert_not_null(pdu_meta, "");
238 	zassert_not_null(pdu_meta->meta, "");
239 	zassert_not_null(pdu_meta->pdu, "");
240 
241 	return isoal_test_insert_segment(true, true, 0, dataptr, length, pdu_meta);
242 }
243 
244 /**
245  * Intializes a TX PDU buffer
246  * @param[in] buf Pointer to buffer structure
247  */
isoal_test_init_tx_pdu_buffer(struct tx_pdu_meta_buffer * buf)248 void isoal_test_init_tx_pdu_buffer(struct tx_pdu_meta_buffer *buf)
249 {
250 	memset(buf, 0, sizeof(struct tx_pdu_meta_buffer));
251 }
252 
253 /**
254  * Initializes a TX SDU buffer
255  * @param[in] buf Pointer to buffer structure
256  */
isoal_test_init_tx_sdu_buffer(struct tx_sdu_frag_buffer * buf)257 void isoal_test_init_tx_sdu_buffer(struct tx_sdu_frag_buffer *buf)
258 {
259 	memset(buf, 0, sizeof(struct tx_sdu_frag_buffer));
260 	buf->sdu_tx.dbuf = buf->sdu_payload;
261 }
262 
263 /**
264  * Initialize the given test data buffer with a ramp pattern
265  * @param buf  Test data buffer pointer
266  * @param size Length of test data
267  */
init_test_data_buffer(uint8_t * buf,uint16_t size)268 void init_test_data_buffer(uint8_t *buf, uint16_t size)
269 {
270 	zassert_not_null(buf, "");
271 
272 	for (uint16_t i = 0; i < size; i++) {
273 		buf[i] = (uint8_t)(i & 0x00FF);
274 	}
275 }
276