1 /******************************************************************************
\r
3 * Copyright (c) 2019 Intel.
\r
5 * Licensed under the Apache License, Version 2.0 (the "License");
\r
6 * you may not use this file except in compliance with the License.
\r
7 * You may obtain a copy of the License at
\r
9 * http://www.apache.org/licenses/LICENSE-2.0
\r
11 * Unless required by applicable law or agreed to in writing, software
\r
12 * distributed under the License is distributed on an "AS IS" BASIS,
\r
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
14 * See the License for the specific language governing permissions and
\r
15 * limitations under the License.
\r
17 *******************************************************************************/
\r
20 * @brief This file provides the implementation of User Plane Messages APIs.
\r
22 * @file xran_up_api.c
\r
23 * @ingroup group_lte_source_xran
\r
24 * @author Intel Corporation
\r
27 #include <inttypes.h>
\r
29 #include <rte_memcpy.h>
\r
30 #include <rte_mbuf.h>
\r
32 #include "xran_fh_o_du.h"
\r
33 #include "xran_transport.h"
\r
34 #include "xran_up_api.h"
\r
35 #include "xran_printf.h"
\r
36 #include "xran_mlog_lnx.h"
\r
38 extern uint32_t xran_lib_ota_tti;
\r
41 * @brief Builds eCPRI header in xRAN packet
\r
43 * @param mbuf Initialized rte_mbuf packet
\r
44 * @param iq_data_num_bytes Number of bytes in IQ data buffer
\r
45 * @param iq_data_offset Number of elements already sent
\r
46 * @return int int 0 on success, non zero on failure
\r
48 static int build_ecpri_hdr(struct rte_mbuf *mbuf,
\r
49 const uint32_t iq_data_num_bytes,
\r
50 const uint32_t iq_data_offset,
\r
53 struct xran_ecpri_hdr *ecpri_hdr = (struct xran_ecpri_hdr *)
\r
54 rte_pktmbuf_append(mbuf, sizeof(struct xran_ecpri_hdr));
\r
56 uint16_t iq_samples_bytes_in_mbuf = rte_pktmbuf_tailroom(mbuf) -
\r
57 sizeof(struct radio_app_common_hdr) - sizeof(struct data_section_hdr);
\r
59 iq_samples_bytes_in_mbuf -= (iq_samples_bytes_in_mbuf % alignment);
\r
61 if (NULL == ecpri_hdr)
\r
64 ecpri_hdr->cmnhdr.ecpri_ver = XRAN_ECPRI_VER;
\r
65 ecpri_hdr->cmnhdr.ecpri_resv = 0;
\r
66 ecpri_hdr->cmnhdr.ecpri_concat = 0;
\r
67 ecpri_hdr->cmnhdr.ecpri_mesg_type = ECPRI_IQ_DATA;
\r
69 if (iq_data_offset + iq_samples_bytes_in_mbuf > iq_data_num_bytes) {
\r
70 ecpri_hdr->cmnhdr.ecpri_payl_size =
\r
71 rte_cpu_to_be_16(sizeof(struct radio_app_common_hdr) +
\r
72 sizeof(struct data_section_hdr) +
\r
73 (iq_data_num_bytes - iq_data_offset) +
\r
74 xran_get_ecpri_hdr_size());
\r
75 ecpri_hdr->ecpri_seq_id.e_bit = 1; /* last segment */
\r
77 ecpri_hdr->cmnhdr.ecpri_payl_size =
\r
78 rte_cpu_to_be_16(sizeof(struct radio_app_common_hdr) +
\r
79 sizeof(struct data_section_hdr) +
\r
80 iq_samples_bytes_in_mbuf +
\r
81 xran_get_ecpri_hdr_size());
\r
82 ecpri_hdr->ecpri_seq_id.e_bit = 0;
\r
85 // ecpri_hdr->ecpri_xtc_id = 0; /* currently not used */
\r
86 ecpri_hdr->ecpri_seq_id.seq_id = 0;
\r
87 ecpri_hdr->ecpri_seq_id.sub_seq_id = iq_data_offset /
\r
88 iq_samples_bytes_in_mbuf;
\r
94 * @brief Builds eCPRI header in xRAN packet
\r
96 * @param mbuf Initialized rte_mbuf packet
\r
97 * @param ecpri_mesg_type eCPRI message type
\r
98 * @param payl_size the size in bytes of the payload part of eCPRI message
\r
99 * @param CC_ID Component Carrier ID for ecpriRtcid/ecpriPcid
\r
100 * @param Ant_ID Antenna ID for ecpriRtcid/ecpriPcid
\r
101 * @param seq_id Message identifier for eCPRI message
\r
102 * @param comp_meth Compression method
\r
103 * @return int int 0 on success, non zero on failure
\r
105 static int xran_build_ecpri_hdr_ex(struct rte_mbuf *mbuf,
\r
106 uint8_t ecpri_mesg_type,
\r
113 char *pChar = rte_pktmbuf_mtod(mbuf, char*);
\r
114 struct xran_ecpri_hdr *ecpri_hdr = (struct xran_ecpri_hdr *)(pChar + sizeof(struct ether_hdr));
\r
115 uint16_t ecpri_payl_size = payl_size
\r
116 + sizeof(struct data_section_hdr)
\r
117 + sizeof(struct radio_app_common_hdr)
\r
118 + xran_get_ecpri_hdr_size();
\r
120 if (comp_meth != XRAN_COMPMETHOD_NONE)
\r
121 ecpri_payl_size += sizeof(struct data_section_compression_hdr);
\r
123 if (NULL == ecpri_hdr)
\r
126 ecpri_hdr->cmnhdr.ecpri_ver = XRAN_ECPRI_VER;
\r
127 ecpri_hdr->cmnhdr.ecpri_resv = 0; // should be zero
\r
128 ecpri_hdr->cmnhdr.ecpri_concat = 0;
\r
129 ecpri_hdr->cmnhdr.ecpri_mesg_type = ecpri_mesg_type;
\r
130 ecpri_hdr->cmnhdr.ecpri_payl_size = rte_cpu_to_be_16(ecpri_payl_size);
\r
132 /* one to one lls-CU to RU only and band sector is the same */
\r
133 ecpri_hdr->ecpri_xtc_id = xran_compose_cid(0, 0, CC_ID, Ant_ID);
\r
135 ecpri_hdr->ecpri_seq_id.seq_id = seq_id;
\r
137 /* no transport layer fragmentation supported */
\r
138 ecpri_hdr->ecpri_seq_id.sub_seq_id = 0;
\r
139 ecpri_hdr->ecpri_seq_id.e_bit = 1;
\r
146 * @brief Builds application layer of xRAN packet
\r
148 * @param mbuf Initialized rte_mbuf packet
\r
149 * @param app_hdr_input Radio App common header structure to be set in mbuf
\r
151 * @return int 0 on success, non zero on failure
\r
153 static int build_application_layer(
\r
154 struct rte_mbuf *mbuf,
\r
155 const struct radio_app_common_hdr *app_hdr_input)
\r
157 char *pChar = rte_pktmbuf_mtod(mbuf, char*);
\r
158 struct radio_app_common_hdr *app_hdr = (struct radio_app_common_hdr *)(pChar + sizeof(struct ether_hdr)
\r
159 + sizeof (struct xran_ecpri_hdr));
\r
161 if (NULL == app_hdr)
\r
164 rte_memcpy(app_hdr, app_hdr_input, sizeof(struct radio_app_common_hdr));
\r
170 * @brief Builds section header in xRAN packet
\r
172 * @param mbuf Initialized rte_mbuf packet
\r
173 * @param sec_hdr Section header structure to be set in mbuf packet
\r
174 * @return int 0 on success, non zero on failure
\r
176 static int build_section_hdr(
\r
177 struct rte_mbuf *mbuf,
\r
178 const struct data_section_hdr *sec_hdr)
\r
180 char *pChar = rte_pktmbuf_mtod(mbuf, char*);
\r
181 struct data_section_hdr *section_hdr = (struct data_section_hdr *)
\r
182 (pChar + sizeof(struct ether_hdr) + sizeof (struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr));
\r
184 if (NULL == section_hdr)
\r
187 rte_memcpy(section_hdr, sec_hdr, sizeof(struct data_section_hdr));
\r
192 * @brief Function for appending IQ samples data to the mbuf.
\r
194 * @param mbuf Initialized rte_mbuf packet.
\r
195 * @param iq_data_start Address of the first element in IQ data array.
\r
196 * @param iq_data_num_bytes Size of the IQ data array.
\r
197 * @param iq_data_offset IQ data btyes already sent.
\r
198 * @return uint16_t Bytes that have been appended to the packet.
\r
200 static uint16_t append_iq_samples_ex(
\r
201 struct rte_mbuf *mbuf,
\r
202 const void *iq_data_start,
\r
203 const uint32_t iq_data_num_bytes,
\r
204 enum xran_input_byte_order iq_buf_byte_order,
\r
207 char *pChar = rte_pktmbuf_mtod(mbuf, char*);
\r
208 void *iq_sam_buf = (pChar + sizeof(struct ether_hdr) + sizeof (struct xran_ecpri_hdr)
\r
209 + sizeof(struct radio_app_common_hdr)
\r
210 + sizeof(struct data_section_hdr));
\r
212 if (iq_sam_buf == NULL){
\r
213 print_err("iq_sam_buf == NULL\n");
\r
216 if(iq_buf_byte_order == XRAN_CPU_LE_BYTE_ORDER){
\r
218 uint16_t *psrc = (uint16_t *)iq_data_start;
\r
219 uint16_t *pdst = (uint16_t *)iq_sam_buf;
\r
220 /* CPU byte order (le) of IQ to network byte order (be) */
\r
221 for (idx = 0; idx < iq_data_num_bytes/sizeof(int16_t); idx++){
\r
222 pdst[idx] = (psrc[idx]>>8) | (psrc[idx]<<8); //rte_cpu_to_be_16(psrc[idx]);
\r
227 /* do not expect to do copy anymore */
\r
228 else if(iq_buf_byte_order == XRAN_NE_BE_BYTE_ORDER){
\r
230 rte_memcpy(iq_sam_buf, (uint8_t *)iq_data_start, iq_data_num_bytes);
\r
235 return iq_data_num_bytes;
\r
239 * @brief Function for appending IQ samples data to the mbuf.
\r
241 * @param mbuf Initialized rte_mbuf packet.
\r
242 * @param iq_data_start Address of the first element in IQ data array.
\r
243 * @param iq_data_num_bytes Size of the IQ data array.
\r
244 * @param iq_data_offset IQ data btyes already sent.
\r
245 * @return uint16_t Bytes that have been appended to the packet.
\r
247 static uint16_t append_iq_samples(
\r
248 struct rte_mbuf *mbuf,
\r
249 const void *iq_data_start,
\r
250 const uint32_t iq_data_num_bytes,
\r
251 const uint32_t iq_data_offset,
\r
252 const uint8_t alignment)
\r
254 uint16_t iq_bytes_to_send = 0;
\r
255 uint16_t free_space_in_pkt = rte_pktmbuf_tailroom(mbuf);
\r
257 if (free_space_in_pkt > iq_data_num_bytes - iq_data_offset)
\r
258 iq_bytes_to_send = iq_data_num_bytes - iq_data_offset;
\r
260 iq_bytes_to_send = free_space_in_pkt;
\r
262 /* don't cut off an iq in half */
\r
263 iq_bytes_to_send -= iq_bytes_to_send % alignment;
\r
265 void *iq_sam_buf = (void *)rte_pktmbuf_append(mbuf, iq_bytes_to_send);
\r
267 rte_memcpy(iq_sam_buf, (uint8_t *)iq_data_start + iq_data_offset,
\r
270 return iq_bytes_to_send;
\r
274 * @brief Builds compression header in xRAN packet
\r
276 * @param mbuf Initialized rte_mbuf packet
\r
277 * @param compression_hdr Section compression header structure
\r
278 * to be set in mbuf packet
\r
279 * @return int 0 on success, non zero on failure
\r
281 static int build_compression_hdr(
\r
282 struct rte_mbuf *mbuf,
\r
283 const struct data_section_compression_hdr *compr_hdr)
\r
285 char *pChar = rte_pktmbuf_mtod(mbuf, char*);
\r
286 struct data_section_compression_hdr *compression_hdr = (struct data_section_compression_hdr *)
\r
287 (pChar + sizeof(struct ether_hdr) + sizeof (struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr)
\r
288 + sizeof(struct data_section_hdr));
\r
290 if (NULL == compression_hdr)
\r
293 rte_memcpy(compression_hdr, compr_hdr, sizeof(*compression_hdr));
\r
299 * @brief Appends compression parameter in xRAN packet
\r
301 * @param mbuf Initialized rte_mbuf packet
\r
302 * @param ud_comp_paramr Compression param to be set in mbuf packet
\r
303 * @return int 0 on success, non zero on failure
\r
305 static int append_comp_param(struct rte_mbuf *mbuf, union compression_params *ud_comp_param)
\r
307 union compression_params *compr_param =
\r
308 (union compression_params *)rte_pktmbuf_append(mbuf, sizeof(union compression_params));
\r
310 if (NULL == compr_param)
\r
313 rte_memcpy(compr_param, ud_comp_param, sizeof(union compression_params));
\r
319 * @brief Function for extracting all IQ samples from xRAN packet
\r
320 * holding a single data section
\r
321 * @param iq_data_start Address of the first element in IQ data array.
\r
322 * @param symb_id Symbol ID to be extracted from ecpri header
\r
323 * @param seq_id Sequence ID to be extracted from radio header
\r
324 * @return int Size of remaining mbuf filled with IQ samples
\r
327 int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
\r
328 void **iq_data_start,
\r
332 uint8_t *subframe_id,
\r
335 struct ecpri_seq_id *seq_id,
\r
336 uint16_t *num_prbu,
\r
337 uint16_t *start_prbu,
\r
341 int8_t expect_comp,
\r
346 uint32_t mlogVar[10];
\r
347 uint32_t mlogVarCnt = 0;
\r
349 struct xran_eaxc_info result;
\r
353 if (NULL == iq_data_start)
\r
356 /* Process eCPRI header. */
\r
357 const struct xran_ecpri_hdr *ecpri_hdr = rte_pktmbuf_mtod(mbuf, void *);
\r
358 if (ecpri_hdr == NULL)
\r
362 *seq_id = ecpri_hdr->ecpri_seq_id;
\r
364 xran_decompose_cid((uint16_t)ecpri_hdr->ecpri_xtc_id, &result);
\r
366 *CC_ID = result.ccId;
\r
367 *Ant_ID = result.ruPortId;
\r
369 /* Process radio header. */
\r
370 struct radio_app_common_hdr *radio_hdr =
\r
371 (void *)rte_pktmbuf_adj(mbuf, sizeof(*ecpri_hdr));
\r
372 if (radio_hdr == NULL)
\r
373 return 0; /* packet too short */
\r
375 radio_hdr->sf_slot_sym.value = rte_be_to_cpu_16(radio_hdr->sf_slot_sym.value);
\r
378 *frame_id = radio_hdr->frame_id;
\r
381 *subframe_id = radio_hdr->sf_slot_sym.subframe_id;
\r
384 *slot_id = radio_hdr->sf_slot_sym.slot_id;
\r
387 *symb_id = radio_hdr->sf_slot_sym.symb_id;
\r
389 /* Process data section hdr */
\r
390 struct data_section_hdr *data_hdr =
\r
391 (void *)rte_pktmbuf_adj(mbuf, sizeof(*radio_hdr));
\r
392 if (data_hdr == NULL)
\r
393 return 0; /* packet too short */
\r
395 /* cpu byte order */
\r
396 data_hdr->fields.all_bits = rte_be_to_cpu_32(data_hdr->fields.all_bits);
\r
398 *num_prbu = data_hdr->fields.num_prbu;
\r
399 *start_prbu = data_hdr->fields.start_prbu;
\r
400 *sym_inc = data_hdr->fields.sym_inc;
\r
401 *rb = data_hdr->fields.rb;
\r
402 *sect_id = data_hdr->fields.sect_id;
\r
405 const struct data_section_compression_hdr *data_compr_hdr =
\r
406 (void *) rte_pktmbuf_adj(mbuf, sizeof(*data_hdr));
\r
408 if (data_compr_hdr == NULL)
\r
411 *compMeth = data_compr_hdr->ud_comp_hdr.ud_comp_meth;
\r
412 *iqWidth = data_compr_hdr->ud_comp_hdr.ud_iq_width;
\r
414 const uint8_t *compr_param =
\r
415 (void *)rte_pktmbuf_adj(mbuf, sizeof(*data_compr_hdr));
\r
417 *iq_data_start = (void *)compr_param; /*rte_pktmbuf_adj(mbuf, sizeof(*compr_param))*/;
\r
419 *iq_data_start = rte_pktmbuf_adj(mbuf, sizeof(*data_hdr));
\r
422 if (*iq_data_start == NULL)
\r
426 mlogVar[mlogVarCnt++] = 0xBBBBBBBB;
\r
427 mlogVar[mlogVarCnt++] = xran_lib_ota_tti;
\r
428 mlogVar[mlogVarCnt++] = radio_hdr->frame_id;
\r
429 mlogVar[mlogVarCnt++] = radio_hdr->sf_slot_sym.subframe_id;
\r
430 mlogVar[mlogVarCnt++] = radio_hdr->sf_slot_sym.slot_id;
\r
431 mlogVar[mlogVarCnt++] = radio_hdr->sf_slot_sym.symb_id;
\r
432 mlogVar[mlogVarCnt++] = data_hdr->fields.sect_id;
\r
433 mlogVar[mlogVarCnt++] = data_hdr->fields.start_prbu;
\r
434 mlogVar[mlogVarCnt++] = data_hdr->fields.num_prbu;
\r
435 mlogVar[mlogVarCnt++] = rte_pktmbuf_pkt_len(mbuf);
\r
436 MLogAddVariables(mlogVarCnt, mlogVar, MLogTick());
\r
439 return rte_pktmbuf_pkt_len(mbuf);
\r
443 * @brief Function for starting preparion of IQ samples portions
\r
444 * to be sent in xRAN packet
\r
446 * @param mbuf Initialized rte_mbuf packet.
\r
447 * @param iq_data_start Address of the first element in IQ data array.
\r
448 * @param iq_data_num_bytes Size of the IQ data array.
\r
449 * @param iq_data_offset IQ data bytes already sent.
\r
450 * @param alignment Size of IQ data alignment.
\r
451 * @param pkt_gen_params Struct with parameters used for building packet
\r
452 * @return int Number of bytes that have been appended
\r
453 to the packet within all appended sections.
\r
455 int32_t xran_prepare_iq_symbol_portion(
\r
456 struct rte_mbuf *mbuf,
\r
457 const void *iq_data_start,
\r
458 const enum xran_input_byte_order iq_buf_byte_order,
\r
459 const uint32_t iq_data_num_bytes,
\r
460 struct xran_up_pkt_gen_params *params,
\r
466 if(xran_build_ecpri_hdr_ex(mbuf,
\r
472 params->compr_hdr_param.ud_comp_hdr.ud_comp_meth)){
\r
473 print_err("xran_build_ecpri_hdr_ex return 0\n");
\r
477 if (build_application_layer(mbuf, &(params->app_params)) != 0){
\r
478 print_err("build_application_layer return != 0\n");
\r
482 if (build_section_hdr(mbuf, &(params->sec_hdr)) != 0){
\r
483 print_err("build_section_hdr return != 0\n");
\r
488 if(params->compr_hdr_param.ud_comp_hdr.ud_comp_meth != XRAN_COMPMETHOD_NONE) {
\r
489 if (build_compression_hdr(mbuf, &(params->compr_hdr_param)) !=0)
\r
492 /* payload expected to start with udCompParam */
\r
494 /*if(append_comp_param(mbuf, &(params->compr_param)) !=0)
\r
499 return append_iq_samples_ex(mbuf, iq_data_start, iq_data_num_bytes, iq_buf_byte_order, do_copy);
\r