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