Update to odulow per maintenance bronze
[o-du/phy.git] / fhi_lib / lib / src / xran_up_api.c
1 /******************************************************************************
2 *
3 *   Copyright (c) 2019 Intel.
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 *
17 *******************************************************************************/
18
19 /**
20  * @brief This file provides the implementation of User Plane Messages APIs.
21  *
22  * @file xran_up_api.c
23  * @ingroup group_lte_source_xran
24  * @author Intel Corporation
25  *
26  **/
27 #include <inttypes.h>
28
29 #include <rte_memcpy.h>
30 #include <rte_mbuf.h>
31
32 #include "xran_fh_o_du.h"
33 #include "xran_transport.h"
34 #include "xran_up_api.h"
35 #include "xran_printf.h"
36 #include "xran_mlog_lnx.h"
37 #include "xran_common.h"
38
39 extern uint32_t xran_lib_ota_tti;
40
41 /**
42  * @brief Builds eCPRI header in xRAN packet
43  *
44  * @param mbuf Initialized rte_mbuf packet
45  * @param iq_data_num_bytes Number of bytes in IQ data buffer
46  * @param iq_data_offset Number of elements already sent
47  * @return int int 0 on success, non zero on failure
48  */
49 static int build_ecpri_hdr(struct rte_mbuf *mbuf,
50     const uint32_t iq_data_num_bytes,
51     const uint32_t iq_data_offset,
52     uint8_t alignment)
53 {
54     struct xran_ecpri_hdr *ecpri_hdr = (struct xran_ecpri_hdr *)
55         rte_pktmbuf_append(mbuf, sizeof(struct xran_ecpri_hdr));
56
57     uint16_t iq_samples_bytes_in_mbuf = rte_pktmbuf_tailroom(mbuf) -
58         sizeof(struct radio_app_common_hdr) - sizeof(struct data_section_hdr);
59
60     iq_samples_bytes_in_mbuf -= (iq_samples_bytes_in_mbuf % alignment);
61
62     if (NULL == ecpri_hdr)
63         return 1;
64
65     ecpri_hdr->cmnhdr.ecpri_ver = XRAN_ECPRI_VER;
66     ecpri_hdr->cmnhdr.ecpri_resv = 0;
67     ecpri_hdr->cmnhdr.ecpri_concat = 0;
68     ecpri_hdr->cmnhdr.ecpri_mesg_type = ECPRI_IQ_DATA;
69
70     if (iq_data_offset + iq_samples_bytes_in_mbuf > iq_data_num_bytes) {
71         ecpri_hdr->cmnhdr.ecpri_payl_size =
72             rte_cpu_to_be_16(sizeof(struct radio_app_common_hdr) +
73                 sizeof(struct data_section_hdr) +
74                 (iq_data_num_bytes - iq_data_offset) +
75                 xran_get_ecpri_hdr_size());
76         ecpri_hdr->ecpri_seq_id.e_bit = 1;  /* last segment */
77     } else {
78         ecpri_hdr->cmnhdr.ecpri_payl_size =
79             rte_cpu_to_be_16(sizeof(struct radio_app_common_hdr) +
80                 sizeof(struct data_section_hdr) +
81                 iq_samples_bytes_in_mbuf +
82                 xran_get_ecpri_hdr_size());
83         ecpri_hdr->ecpri_seq_id.e_bit = 0;
84     }
85
86 //    ecpri_hdr->ecpri_xtc_id = 0;    /* currently not used */
87     ecpri_hdr->ecpri_seq_id.seq_id = 0;
88     ecpri_hdr->ecpri_seq_id.sub_seq_id = iq_data_offset /
89         iq_samples_bytes_in_mbuf;
90
91     return 0;
92 }
93
94 /**
95  * @brief Builds eCPRI header in xRAN packet
96  *
97  * @param mbuf Initialized rte_mbuf packet
98  * @param ecpri_mesg_type eCPRI message type
99  * @param payl_size the size in bytes of the payload part of eCPRI message
100  * @param CC_ID Component Carrier ID for ecpriRtcid/ecpriPcid
101  * @param Ant_ID Antenna ID for ecpriRtcid/ecpriPcid
102  * @param seq_id Message identifier for eCPRI message
103  * @param comp_meth Compression method
104  * @return int int 0 on success, non zero on failure
105  */
106 static int xran_build_ecpri_hdr_ex(struct rte_mbuf *mbuf,
107                               uint8_t ecpri_mesg_type,
108                               int payl_size,
109                               uint8_t CC_ID,
110                               uint8_t Ant_ID,
111                               uint8_t seq_id,
112                               uint8_t comp_meth)
113 {
114     char *pChar = rte_pktmbuf_mtod(mbuf, char*);
115     struct xran_ecpri_hdr *ecpri_hdr = (struct xran_ecpri_hdr *)(pChar + sizeof(struct rte_ether_hdr));
116     uint16_t    ecpri_payl_size = payl_size
117                                 + sizeof(struct data_section_hdr)
118                                 + sizeof(struct radio_app_common_hdr)
119                                 + xran_get_ecpri_hdr_size();
120
121     if (comp_meth != XRAN_COMPMETHOD_NONE)
122         ecpri_payl_size += sizeof(struct data_section_compression_hdr);
123
124     if (NULL == ecpri_hdr)
125         return 1;
126
127     ecpri_hdr->cmnhdr.ecpri_ver       = XRAN_ECPRI_VER;
128     ecpri_hdr->cmnhdr.ecpri_resv      = 0;     // should be zero
129     ecpri_hdr->cmnhdr.ecpri_concat    = 0;
130     ecpri_hdr->cmnhdr.ecpri_mesg_type = ecpri_mesg_type;
131     ecpri_hdr->cmnhdr.ecpri_payl_size = rte_cpu_to_be_16(ecpri_payl_size);
132
133     /* one to one lls-CU to RU only and band sector is the same */
134     ecpri_hdr->ecpri_xtc_id = xran_compose_cid(0, 0, CC_ID, Ant_ID);
135
136     ecpri_hdr->ecpri_seq_id.seq_id = seq_id;
137
138     /* no transport layer fragmentation supported */
139     ecpri_hdr->ecpri_seq_id.sub_seq_id  = 0;
140     ecpri_hdr->ecpri_seq_id.e_bit       = 1;
141
142     return 0;
143 }
144
145
146 /**
147  * @brief Builds application layer of xRAN packet
148  *
149  * @param mbuf Initialized rte_mbuf packet
150  * @param app_hdr_input Radio App common header structure to be set in mbuf
151  *                      packet.
152  * @return int 0 on success, non zero on failure
153  */
154 static int build_application_layer(
155     struct rte_mbuf *mbuf,
156     const struct radio_app_common_hdr *app_hdr_input)
157 {
158     char *pChar = rte_pktmbuf_mtod(mbuf, char*);
159     struct radio_app_common_hdr *app_hdr = (struct radio_app_common_hdr *)(pChar + sizeof(struct rte_ether_hdr)
160         + sizeof (struct xran_ecpri_hdr));
161
162     if (NULL == app_hdr)
163         return 1;
164
165     rte_memcpy(app_hdr, app_hdr_input, sizeof(struct radio_app_common_hdr));
166
167     return 0;
168 }
169
170 /**
171  * @brief Builds section header in xRAN packet
172  *
173  * @param mbuf Initialized rte_mbuf packet
174  * @param sec_hdr Section header structure to be set in mbuf packet
175  * @return int 0 on success, non zero on failure
176  */
177 static int build_section_hdr(
178     struct rte_mbuf *mbuf,
179     const struct data_section_hdr *sec_hdr)
180 {
181     char *pChar = rte_pktmbuf_mtod(mbuf, char*);
182     struct data_section_hdr *section_hdr = (struct data_section_hdr *)
183         (pChar + sizeof(struct rte_ether_hdr) + sizeof (struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr));
184
185     if (NULL == section_hdr)
186         return 1;
187
188     rte_memcpy(section_hdr, sec_hdr, sizeof(struct data_section_hdr));
189
190     return 0;
191 }
192 /**
193  * @brief Function for appending IQ samples data to the mbuf.
194  *
195  * @param mbuf Initialized rte_mbuf packet.
196  * @param iq_data_start Address of the first element in IQ data array.
197  * @param iq_data_num_bytes Size of the IQ data array.
198  * @param iq_data_offset IQ data btyes already sent.
199  * @return uint16_t Bytes that have been appended to the packet.
200  */
201 static uint16_t append_iq_samples_ex(
202     struct rte_mbuf *mbuf,
203     const void *iq_data_start,
204     const uint32_t iq_data_num_bytes,
205     enum xran_input_byte_order iq_buf_byte_order,
206     uint32_t do_copy)
207 {
208     char *pChar = rte_pktmbuf_mtod(mbuf, char*);
209     void *iq_sam_buf  = (pChar + sizeof(struct rte_ether_hdr) + sizeof (struct xran_ecpri_hdr)
210                         + sizeof(struct radio_app_common_hdr)
211                         + sizeof(struct data_section_hdr));
212
213     if (iq_sam_buf == NULL){
214         print_err("iq_sam_buf == NULL\n");
215         return 0;
216     }
217     if(iq_buf_byte_order == XRAN_CPU_LE_BYTE_ORDER){
218         int idx = 0;
219         uint16_t *psrc = (uint16_t *)iq_data_start;
220         uint16_t *pdst = (uint16_t *)iq_sam_buf;
221         /* CPU byte order (le) of IQ to network byte order (be) */
222         for (idx = 0; idx < iq_data_num_bytes/sizeof(int16_t); idx++){
223             pdst[idx]  =  (psrc[idx]>>8) | (psrc[idx]<<8); //rte_cpu_to_be_16(psrc[idx]);
224         }
225     }
226
227     else if(iq_buf_byte_order == XRAN_NE_BE_BYTE_ORDER){
228         if(do_copy) {
229            rte_memcpy(iq_sam_buf, (uint8_t *)iq_data_start,  iq_data_num_bytes);
230         }
231     }
232
233     return iq_data_num_bytes;
234 }
235
236 /**
237  * @brief Function for appending IQ samples data to the mbuf.
238  *
239  * @param mbuf Initialized rte_mbuf packet.
240  * @param iq_data_start Address of the first element in IQ data array.
241  * @param iq_data_num_bytes Size of the IQ data array.
242  * @param iq_data_offset IQ data btyes already sent.
243  * @return uint16_t Bytes that have been appended to the packet.
244  */
245 static uint16_t append_iq_samples(
246     struct rte_mbuf *mbuf,
247     const void *iq_data_start,
248     const uint32_t iq_data_num_bytes,
249     const uint32_t iq_data_offset,
250     const uint8_t alignment)
251 {
252     uint16_t iq_bytes_to_send = 0;
253     uint16_t free_space_in_pkt = rte_pktmbuf_tailroom(mbuf);
254
255     if (free_space_in_pkt > iq_data_num_bytes - iq_data_offset)
256         iq_bytes_to_send = iq_data_num_bytes - iq_data_offset;
257     else
258         iq_bytes_to_send = free_space_in_pkt;
259
260     /* don't cut off an iq in half */
261     iq_bytes_to_send -= iq_bytes_to_send % alignment;
262
263     void *iq_sam_buf = (void *)rte_pktmbuf_append(mbuf, iq_bytes_to_send);
264
265     rte_memcpy(iq_sam_buf, (uint8_t *)iq_data_start + iq_data_offset,
266             iq_bytes_to_send);
267
268     return iq_bytes_to_send;
269 }
270
271 /**
272  * @brief Builds compression header in xRAN packet
273  *
274  * @param mbuf Initialized rte_mbuf packet
275  * @param compression_hdr Section compression header structure
276  *                to be set in mbuf packet
277  * @return int 0 on success, non zero on failure
278  */
279 static int build_compression_hdr(
280     struct rte_mbuf *mbuf,
281     const struct data_section_compression_hdr *compr_hdr)
282 {
283     char *pChar = rte_pktmbuf_mtod(mbuf, char*);
284     struct data_section_compression_hdr *compression_hdr = (struct data_section_compression_hdr *)
285         (pChar + sizeof(struct rte_ether_hdr) + sizeof (struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr)
286         + sizeof(struct data_section_hdr));
287
288     if (NULL == compression_hdr)
289         return 1;
290
291     rte_memcpy(compression_hdr, compr_hdr, sizeof(*compression_hdr));
292
293     return 0;
294 }
295
296 /**
297  * @brief Appends compression parameter in xRAN packet
298  *
299  * @param mbuf Initialized rte_mbuf packet
300  * @param ud_comp_paramr Compression param to be set in mbuf packet
301  * @return int 0 on success, non zero on failure
302  */
303 static int append_comp_param(struct rte_mbuf *mbuf, union compression_params *ud_comp_param)
304 {
305     union compression_params *compr_param =
306         (union compression_params *)rte_pktmbuf_append(mbuf, sizeof(union compression_params));
307
308     if (NULL == compr_param)
309         return 1;
310
311     rte_memcpy(compr_param, ud_comp_param, sizeof(union compression_params));
312
313     return 0;
314 }
315
316 /**
317  * @brief Function for extracting all IQ samples from xRAN packet
318  *        holding a single data section
319  * @param iq_data_start Address of the first element in IQ data array.
320  * @param symb_id Symbol ID to be extracted from ecpri header
321  * @param seq_id  Sequence ID to be extracted from radio header
322  * @return int Size of remaining mbuf filled with IQ samples
323                zero on failure
324  */
325 int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
326     void **iq_data_start,
327     uint8_t *CC_ID,
328     uint8_t *Ant_ID,
329     uint8_t *frame_id,
330     uint8_t *subframe_id,
331     uint8_t *slot_id,
332     uint8_t *symb_id,
333     struct ecpri_seq_id *seq_id,
334     uint16_t *num_prbu,
335     uint16_t *start_prbu,
336     uint16_t *sym_inc,
337     uint16_t *rb,
338     uint16_t *sect_id,
339     int8_t   expect_comp,
340     uint8_t *compMeth,
341     uint8_t *iqWidth)
342 {
343 #if XRAN_MLOG_VAR
344     uint32_t mlogVar[10];
345     uint32_t mlogVarCnt = 0;
346 #endif
347     struct xran_eaxc_info result;
348
349     if (NULL == mbuf)
350         return 0;
351     if (NULL == iq_data_start)
352         return 0;
353
354     /* Process eCPRI header. */
355     const struct xran_ecpri_hdr *ecpri_hdr = rte_pktmbuf_mtod(mbuf, void *);
356     if (ecpri_hdr == NULL)
357         return 0;
358
359     if (seq_id)
360         *seq_id = ecpri_hdr->ecpri_seq_id;
361
362     xran_decompose_cid((uint16_t)ecpri_hdr->ecpri_xtc_id, &result);
363
364     *CC_ID  = result.ccId;
365     *Ant_ID = result.ruPortId;
366
367     /* Process radio header. */
368     struct radio_app_common_hdr *radio_hdr =
369         (void *)rte_pktmbuf_adj(mbuf, sizeof(*ecpri_hdr));
370     if (radio_hdr == NULL)
371         return 0;       /* packet too short */
372
373     radio_hdr->sf_slot_sym.value = rte_be_to_cpu_16(radio_hdr->sf_slot_sym.value);
374
375     if (frame_id)
376         *frame_id    = radio_hdr->frame_id;
377
378     if (subframe_id)
379         *subframe_id = radio_hdr->sf_slot_sym.subframe_id;
380
381     if (slot_id)
382         *slot_id     = xran_slotid_convert(radio_hdr->sf_slot_sym.slot_id, 1);
383
384     if (symb_id)
385         *symb_id = radio_hdr->sf_slot_sym.symb_id;
386
387     /* Process data section hdr */
388     struct data_section_hdr *data_hdr =
389         (void *)rte_pktmbuf_adj(mbuf, sizeof(*radio_hdr));
390     if (data_hdr == NULL)
391         return 0;       /* packet too short */
392
393     /* cpu byte order */
394     data_hdr->fields.all_bits  = rte_be_to_cpu_32(data_hdr->fields.all_bits);
395
396     *num_prbu   = data_hdr->fields.num_prbu;
397     *start_prbu = data_hdr->fields.start_prbu;
398     *sym_inc    = data_hdr->fields.sym_inc;
399     *rb         = data_hdr->fields.rb;
400     *sect_id    = data_hdr->fields.sect_id;
401
402     if(expect_comp) {
403         const struct data_section_compression_hdr *data_compr_hdr =
404             (void *) rte_pktmbuf_adj(mbuf, sizeof(*data_hdr));
405
406         if (data_compr_hdr == NULL)
407             return 0;
408
409         *compMeth = data_compr_hdr->ud_comp_hdr.ud_comp_meth;
410         *iqWidth =  data_compr_hdr->ud_comp_hdr.ud_iq_width;
411
412         const uint8_t *compr_param =
413             (void *)rte_pktmbuf_adj(mbuf, sizeof(*data_compr_hdr));
414
415             *iq_data_start = (void *)compr_param; /*rte_pktmbuf_adj(mbuf, sizeof(*compr_param))*/;
416     } else {
417         *iq_data_start = rte_pktmbuf_adj(mbuf, sizeof(*data_hdr));
418     }
419
420     if (*iq_data_start == NULL)
421         return 0;
422
423 #if XRAN_MLOG_VAR
424     mlogVar[mlogVarCnt++] = 0xBBBBBBBB;
425     mlogVar[mlogVarCnt++] = xran_lib_ota_tti;
426     mlogVar[mlogVarCnt++] = radio_hdr->frame_id;
427     mlogVar[mlogVarCnt++] = radio_hdr->sf_slot_sym.subframe_id;
428     mlogVar[mlogVarCnt++] = radio_hdr->sf_slot_sym.slot_id;
429     mlogVar[mlogVarCnt++] = radio_hdr->sf_slot_sym.symb_id;
430     mlogVar[mlogVarCnt++] = data_hdr->fields.sect_id;
431     mlogVar[mlogVarCnt++] = data_hdr->fields.start_prbu;
432     mlogVar[mlogVarCnt++] = data_hdr->fields.num_prbu;
433     mlogVar[mlogVarCnt++] = rte_pktmbuf_pkt_len(mbuf);
434     MLogAddVariables(mlogVarCnt, mlogVar, MLogTick());
435 #endif
436
437     return rte_pktmbuf_pkt_len(mbuf);
438 }
439
440 /**
441  * @brief Function for starting preparion of IQ samples portions
442  *        to be sent in xRAN packet
443  *
444  * @param mbuf Initialized rte_mbuf packet.
445  * @param iq_data_start Address of the first element in IQ data array.
446  * @param iq_data_num_bytes Size of the IQ data array.
447  * @param iq_data_offset IQ data bytes already sent.
448  * @param alignment Size of IQ data alignment.
449  * @param pkt_gen_params Struct with parameters used for building packet
450  * @return int Number of bytes that have been appended
451                to the packet within all appended sections.
452  */
453 int32_t xran_prepare_iq_symbol_portion(
454                         struct rte_mbuf *mbuf,
455                         const void *iq_data_start,
456                         const enum xran_input_byte_order iq_buf_byte_order,
457                         const uint32_t iq_data_num_bytes,
458                         struct xran_up_pkt_gen_params *params,
459                         uint8_t CC_ID,
460                         uint8_t Ant_ID,
461                         uint8_t seq_id,
462                         uint32_t do_copy)
463 {
464     if(xran_build_ecpri_hdr_ex(mbuf,
465                            ECPRI_IQ_DATA,
466                            iq_data_num_bytes,
467                            CC_ID,
468                            Ant_ID,
469                            seq_id,
470                            params->compr_hdr_param.ud_comp_hdr.ud_comp_meth)){
471         print_err("xran_build_ecpri_hdr_ex return 0\n");
472         return 0;
473     }
474
475     if (build_application_layer(mbuf, &(params->app_params)) != 0){
476         print_err("build_application_layer return != 0\n");
477         return 0;
478     }
479
480     if (build_section_hdr(mbuf, &(params->sec_hdr)) != 0){
481         print_err("build_section_hdr return != 0\n");
482         return 0;
483     }
484
485
486     if(params->compr_hdr_param.ud_comp_hdr.ud_comp_meth != XRAN_COMPMETHOD_NONE) {
487         if (build_compression_hdr(mbuf, &(params->compr_hdr_param)) !=0)
488             return 0;
489
490          /* payload expected to start with udCompParam */
491
492         /*if(append_comp_param(mbuf, &(params->compr_param)) !=0)
493             return 0;*/
494     }
495
496
497     return append_iq_samples_ex(mbuf, iq_data_start, iq_data_num_bytes, iq_buf_byte_order, do_copy);
498 }
499