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