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