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