diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 6a0f6e15388c9c045dd7032405baca948b7364c0..e62d8fe33c95df999868bd43e3dc73f0bd2c46a9 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -1298,14 +1298,35 @@ set(PHY_SMALLBLOCKSRC
 set(PHY_TURBOIF
   ${OPENAIR1_DIR}/PHY/CODING/coding_load.c
 )
-set(PHY_LDPCSRC
+
+set(PHY_LDPC_ORIG_SRC
   ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
   ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c
-  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder2.c
-  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c
 )
 
+set(PHY_LDPC_OPTIM_SRC
+  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
+  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c
+)
+set(PHY_LDPC_OPTIM8SEG_SRC
+  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
+  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c
+)
+set(PHY_LDPC_OPTIM8SEGMULTI_SRC
+  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
+  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
+)
+set(PHY_NR_CODINGIF
+  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c;
+)
+
+add_library(ldpc_orig MODULE ${PHY_LDPC_ORIG_SRC} )
+add_library(ldpc_optim MODULE ${PHY_LDPC_OPTIM_SRC} )
+add_library(ldpc_optim8seg MODULE ${PHY_LDPC_OPTIM8SEG_SRC} )
+add_library(ldpc MODULE ${PHY_LDPC_OPTIM8SEGMULTI_SRC} )
+
 add_library(coding MODULE ${PHY_TURBOSRC} )
+
 set(PHY_SRC_COMMON
   ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools_common.c
   ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/lte_mcs.c
@@ -1485,10 +1506,9 @@ set(PHY_SRC_UE
   ${OPENAIR1_DIR}/PHY/TOOLS/lut.c
   ${PHY_POLARSRC}
   ${PHY_SMALLBLOCKSRC}
-  ${PHY_LDPCSRC}
+  ${PHY_NR_CODINGIF}
   ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/pucch_rx.c 
   )
-
   set(PHY_NR_UE_SRC
   ${OPENAIR1_DIR}/PHY/INIT/nr_parms.c
   ${OPENAIR1_DIR}/PHY/MODULATION/nr_modulation.c
@@ -1537,7 +1557,7 @@ set(PHY_SRC_UE
   #  ${OPENAIR1_DIR}/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_test.c
   ${PHY_POLARSRC}
   ${PHY_SMALLBLOCKSRC}
-  ${PHY_LDPCSRC}
+  ${PHY_NR_CODINGIF}
   )
 
 
@@ -2590,7 +2610,7 @@ target_link_libraries (nr-softmodem pthread m ${CONFIG_LIB} rt crypt ${CRYPTO_LI
 target_link_libraries (nr-softmodem ${LIB_LMS_LIBRARIES})
 target_link_libraries (nr-softmodem ${T_LIB})
 
-
+add_dependencies( nr-softmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc )
 # nr-uesoftmodem is  UE implementation
 #######################################
 
@@ -2631,7 +2651,7 @@ target_link_libraries (nr-uesoftmodem pthread m ${CONFIG_LIB} rt crypt ${CRYPTO_
 target_link_libraries (nr-uesoftmodem ${LIB_LMS_LIBRARIES})
 target_link_libraries (nr-uesoftmodem ${T_LIB})
 
-
+add_dependencies( nr-uesoftmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc )
 
 # USIM process
 #################
@@ -2698,10 +2718,13 @@ target_link_libraries(smallblocktest
   )
 
 add_executable(ldpctest  
+  ${PHY_NR_CODINGIF}
   ${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/ldpctest.c
   ${T_SOURCE}
   ${SHLIB_LOADER_SOURCES}
   )
+add_dependencies( ldpctest ldpc_orig ldpc_optim ldpc_optim8seg ldpc ) 
+
 target_link_libraries(ldpctest
   -Wl,--start-group UTIL SIMU PHY_NR CONFIG_LIB -Wl,--end-group
   m pthread ${ATLAS_LIBRARIES} dl
diff --git a/common/config/config_userapi.c b/common/config/config_userapi.c
index 67fdc2c920c17df6a29d32881875677036a21a7f..c951905101b314eccaf8f5354b1eabb83751a57f 100644
--- a/common/config/config_userapi.c
+++ b/common/config/config_userapi.c
@@ -45,7 +45,8 @@
 
 configmodule_interface_t *config_get_if(void) {
   if (cfgptr == NULL) {
-    CONFIG_PRINTF_ERROR("[CONFIG] %s %d config module not initialized\n",__FILE__,__LINE__);
+  	if (isLogInitDone())
+       LOG_W(ENB_APP,"[CONFIG] %s %d config module not initialized\n",__FILE__,__LINE__);
   }
 
   return cfgptr;
diff --git a/common/utils/telnetsrv/telnetsrv.c b/common/utils/telnetsrv/telnetsrv.c
index 10163b22b5c0a8bb380b762b9608d596fbffbbe2..06a5d350c75a452ef18e325813de53453912d66d 100644
--- a/common/utils/telnetsrv/telnetsrv.c
+++ b/common/utils/telnetsrv/telnetsrv.c
@@ -377,6 +377,14 @@ int setgetvar(int moduleindex,char getorset,char *params) {
             client_printf("%hi\n",*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
             break;
 
+          case TELNET_VARTYPE_INT8:
+            client_printf("%i\n",(int)(*(int8_t *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)));
+            break;
+            
+          case TELNET_VARTYPE_UINT:
+            client_printf("%u\n",*(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
+            break;
+            
           case TELNET_VARTYPE_DOUBLE:
             client_printf("%g\n",*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
             break;
@@ -405,7 +413,17 @@ int setgetvar(int moduleindex,char getorset,char *params) {
             *(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (short)strtol(varval,NULL,0);
             client_printf("%hi\n",*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
             break;
-
+            
+          case TELNET_VARTYPE_INT8:
+            *(char *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (char)strtol(varval,NULL,0);
+            client_printf("%i\n",*(int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
+            break;
+            
+          case TELNET_VARTYPE_UINT:
+            *(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (unsigned int)strtol(varval,NULL,0);
+            client_printf("%u\n",*(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
+            break;
+ 
           case TELNET_VARTYPE_DOUBLE:
             *(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = strtod(varval,NULL);
             client_printf("%g\n",*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
diff --git a/openair1/PHY/CODING/DOC/LDPCImplementation.md b/openair1/PHY/CODING/DOC/LDPCImplementation.md
new file mode 100644
index 0000000000000000000000000000000000000000..89ae6b4dbb64a28935436e59b40b39724f0c7d2e
--- /dev/null
+++ b/openair1/PHY/CODING/DOC/LDPCImplementation.md
@@ -0,0 +1,26 @@
+#LDPC coder/decoder implementation
+The LDPC coder and decoder are implemented in a shared library, dynamically loaded at run-time using the [oai shared library loader](file://../../../../common/utils/DOC/loader.md). The code loading the LDPC library is in [nrLDPC_load.c](file://../nrLDPC_load.c), in function `load_nrLDPClib`, which must be called at init time.
+
+## Selecting the LDPC library at run time
+
+By default the function `int load_nrLDPClib(void)` looks for `libldpc.so`, this default behavior can be changed using the oai loader configuration options in the configuration file or from the command line as shown below:
+
+>loading `libldpc_optim8seg.so` instead of `libldpc.so`
+
+```
+./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5  --loader.ldpc.shlibversion _optim8seg
+.......................
+[CONFIG] loader.ldpc.shlibversion set to default value ""
+[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (1 to default value)
+[CONFIG] shlibversion set to  _optim8seg from command line
+[CONFIG] loader.ldpc 1 options set from command line
+[LOADER] library libldpc_optim8seg.so successfully loaded
+........................
+```
+
+Today, this mechanism is not available in the `ldpctest` phy simulator which doesn't initialize the [configuration module](file://../../../../common/config/DOC/config.md). loads `libldpc.so` and `libldpc_orig.so` to compare the performance of the two implementations.
+
+###LDPC libraries
+Libraries implementing the LDPC algorithms must be named `libldpc<_version>.so`, they must implement two functions: `nrLDPC_decod` and `nrLDPC_encod`. The prototypes for these functions is defined in [nrLDPC_defs.h](file://nrLDPC_defs.h).
+
+[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
diff --git a/openair1/PHY/CODING/TESTBENCH/ldpctest.c b/openair1/PHY/CODING/TESTBENCH/ldpctest.c
index 95ee3fed170f5895f2f6048cb4bfb8f9bfc98686..552af99c41e78e3de1ddf114c3a90fcc13d33e57 100644
--- a/openair1/PHY/CODING/TESTBENCH/ldpctest.c
+++ b/openair1/PHY/CODING/TESTBENCH/ldpctest.c
@@ -25,8 +25,7 @@
 #include <string.h>
 #include "assertions.h"
 #include "SIMULATION/TOOLS/sim.h"
-#include "PHY/CODING/nrLDPC_encoder/defs.h"
-#include "PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h"
+#include "PHY/CODING/nrLDPC_extern.h"
 #include "openair1/SIMULATION/NR_PHY/nr_unitary_defs.h"
 
 #define MAX_NUM_DLSCH_SEGMENTS 16
@@ -85,6 +84,7 @@ typedef struct {
 RAN_CONTEXT_t RC;
 PHY_VARS_UE ***PHY_vars_UE_g;
 uint16_t NB_UE_INST = 1;
+nrLDPC_encoderfunc_t encoder_orig;
 
 short lift_size[51]= {2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,20,22,24,26,28,30,32,36,40,44,48,52,56,60,64,72,80,88,96,104,112,120,128,144,160,176,192,208,224,240,256,288,320,352,384};
 
@@ -286,16 +286,19 @@ int test_ldpc(short No_iteration,
   no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*(1/((float)nom_rate/(float)denom_rate)))/Zc;
   //  printf("puncture:%d\n",no_punctured_columns);
   removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length/((float)nom_rate/(float)denom_rate));
+  encoder_implemparams_t impp=INIT0_LDPCIMPLEMPARAMS;
+ 
+  impp.gen_code=1;
   if (ntrials==0)
-    ldpc_encoder_orig(test_input[0],channel_input[0], Zc, BG, block_length, BG, 1);
-
+    encoder_orig(test_input,channel_input, Zc, BG, block_length, BG, &impp);
+  impp.gen_code=0;
   for (trial=0; trial < ntrials; trial++)
   {
 	segment_bler = 0;
     //// encoder
     start_meas(&time);
     for(j=0;j<n_segments;j++) {
-      ldpc_encoder_orig(test_input[j], channel_input[j],Zc,Kb,block_length,BG,0);
+      encoder_orig(&(test_input[j]), &(channel_input[j]),Zc,Kb,block_length,BG,&impp);
     }
     stop_meas(&time);
 
@@ -305,10 +308,11 @@ int test_ldpc(short No_iteration,
       ldpc_encoder_optim(test_input[j],channel_input_optim[j],Zc,Kb,block_length,BG,&tinput,&tprep,&tparity,&toutput);
       }
     stop_meas(time_optim);*/
-
+    impp.n_segments=n_segments;
     for(j=0;j<(n_segments/8+1);j++) {
     	start_meas(time_optim);
-    	ldpc_encoder_optim_8seg_multi(test_input,channel_input_optim,Zc,Kb,block_length, BG, n_segments,j,&tinput,&tprep,&tparity,&toutput);
+    	impp.macro_num=j;
+    	nrLDPC_encoder(test_input,channel_input_optim,Zc,Kb,block_length, BG, &impp);
     	stop_meas(time_optim);
     }
     
@@ -598,8 +602,8 @@ int main(int argc, char *argv[])
   printf("SNR0 %f: \n", SNR0);
 
 
-
-
+  load_nrLDPClib();
+  load_nrLDPClib_ref("_orig", &encoder_orig);
   //for (block_length=8;block_length<=MAX_BLOCK_LENGTH;block_length+=8)
 
 
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
index d3e851f07bf2fec6e695a7dd9f3c3e924321a4b3..3226c97f8759ed856232277efd052527f68678eb 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
+++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
@@ -31,7 +31,7 @@
 
 #include <stdint.h>
 #include <immintrin.h>
-#include "nrLDPC_defs.h"
+#include "nrLDPCdecoder_defs.h"
 #include "nrLDPC_types.h"
 #include "nrLDPC_init.h"
 #include "nrLDPC_mPass.h"
@@ -47,7 +47,7 @@
 
 static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, t_nrLDPC_procBuf* p_procBuf, uint32_t numLLR, t_nrLDPC_lut* p_lut, t_nrLDPC_dec_params* p_decParams, t_nrLDPC_time_stats* p_profiler);
 
-int32_t nrLDPC_decoder(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out, t_nrLDPC_procBuf* p_procBuf, t_nrLDPC_time_stats* p_profiler)
+int32_t nrLDPC_decod(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out, t_nrLDPC_procBuf* p_procBuf, t_nrLDPC_time_stats* p_profiler)
 {
     uint32_t numLLR;
     uint32_t numIter = 0;
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h
index 82462c6d95a7c0f082a5fa92dbb9b2402736bf26..ea031dc2daee68539a0e4d0450dcdec6be9b525f 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h
+++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h
@@ -32,7 +32,7 @@
 #define __NR_LDPC_INIT__H__
 
 #include "nrLDPC_lut.h"
-#include "nrLDPC_defs.h"
+#include "nrLDPCdecoder_defs.h"
 
 /**
    \brief Initializes the decoder and sets correct LUTs
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init_mem.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init_mem.h
index bdaa118e1f338f9fa8717e9f22b9511ec34304be..3292c0debefc82ffb5ef9dbc71d6c2d39791747d 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init_mem.h
+++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init_mem.h
@@ -32,7 +32,6 @@
 #define __NR_LDPC_INIT_MEM__H__
 
 #include <stdlib.h>
-#include "nrLDPC_defs.h"
 #include "nrLDPC_types.h"
 
 #ifndef malloc32_clear
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h
index 66715618d05b717fe3cf684d137ba9a2a1fe9c64..7d0f5f077a90bd7b00ceebbe4eb07b96149c2d70 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h
+++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h
@@ -32,7 +32,7 @@
 #define __NR_LDPC_MPASS__H__
 
 #include <string.h>
-#include "nrLDPC_defs.h"
+#include "nrLDPCdecoder_defs.h"
 
 /**
    \brief Circular memcpy
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h
index 34322a7780568f86dd4a8bb793b18fc8fffa57d6..e5b99246d533fa14675565e57115343b327d586e 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h
+++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h
@@ -32,8 +32,7 @@
 #define __NR_LDPC_TYPES__H__
 
 #include "PHY/TOOLS/time_meas.h"
-#include "nrLDPC_defs.h"
-
+#include "nrLDPCdecoder_defs.h"
 // ==============================================================================
 // TYPES
 
@@ -103,4 +102,6 @@ typedef struct nrLDPC_procBuf {
     int8_t* llrProcBuf; /**< LLR processing buffer */
 } t_nrLDPC_procBuf;
 
+
+
 #endif
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_defs.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPCdecoder_defs.h
similarity index 99%
rename from openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_defs.h
rename to openair1/PHY/CODING/nrLDPC_decoder/nrLDPCdecoder_defs.h
index 940d842550ea116aa496d3d81a1449e43dd7bb6b..69fc88752fb44b5737ad11a0bd8285f7cba05e86 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_defs.h
+++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPCdecoder_defs.h
@@ -19,7 +19,7 @@
  *      contact@openairinterface.org
  */
 
-/*!\file nrLDPC_defs.h
+/*!\file nrLDPCdecoder_defs.h
  * \brief Defines all constants and buffers for the LDPC decoder
  * \author Sebastian Wagner (TCL Communications) Email: <mailto:sebastian.wagner@tcl.com>
  * \date 27-03-2018
diff --git a/openair1/PHY/CODING/nrLDPC_defs.h b/openair1/PHY/CODING/nrLDPC_defs.h
new file mode 100644
index 0000000000000000000000000000000000000000..b96067f4b6eddfe4ca9e1652689aa69d44074833
--- /dev/null
+++ b/openair1/PHY/CODING/nrLDPC_defs.h
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+//============================================================================================================================
+// encoder interface
+#ifndef __NRLDPC_DEFS__H__
+#define __NRLDPC_DEFS__H__
+#include "openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h"
+/**
+   \brief LDPC encoder
+   \param 1 input
+   \param 2 channel_input
+   \param 3 int Zc
+   \param 4 int Kb
+   \param 5 short block_length
+   \param 6 short BG
+   \param 7 int n_segment
+   \param 8 unsigned int macro_num
+   \param 9-12 time_stats_t *tinput,*tprep, *tparity,*toutput
+*/
+typedef struct {
+	int n_segments;          // optim8seg
+	unsigned int macro_num; // optim8segmulti
+	unsigned char gen_code; //orig
+	time_stats_t *tinput;
+	time_stats_t *tprep;
+	time_stats_t *tparity;
+	time_stats_t *toutput;
+}encoder_implemparams_t;
+#define INIT0_LDPCIMPLEMPARAMS {0,0,0,NULL,NULL,NULL,NULL}
+typedef int(*nrLDPC_encoderfunc_t)(unsigned char **,unsigned char **,int,int,short, short, encoder_implemparams_t*);
+//============================================================================================================================
+// decoder interface
+/**
+   \brief LDPC decoder API type definition
+   \param p_decParams LDPC decoder parameters
+   \param p_llr Input LLRs
+   \param p_llrOut Output vector
+   \param p_profiler LDPC profiler statistics
+*/
+typedef int32_t(*nrLDPC_decoderfunc_t)(t_nrLDPC_dec_params* , int8_t*, int8_t* , t_nrLDPC_procBuf* , t_nrLDPC_time_stats* );
+#endif
\ No newline at end of file
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/defs.h b/openair1/PHY/CODING/nrLDPC_encoder/defs.h
deleted file mode 100644
index 85cb852fe50042ace84d000da4b445e4df851d51..0000000000000000000000000000000000000000
--- a/openair1/PHY/CODING/nrLDPC_encoder/defs.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The OpenAirInterface Software Alliance licenses this file to You under
- * the OAI Public License, Version 1.1  (the "License"); you may not use this file
- * except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.openairinterface.org/?page_id=698
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *-------------------------------------------------------------------------------
- * For more information about the OpenAirInterface (OAI) Software Alliance:
- *      contact@openairinterface.org
- */
-
-/*!\file defs.h
- * \brief LDPC encoder forward declarations
- * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom)
- * \email openair_tech@eurecom.fr
- * \date 27-03-2018
- * \version 1.0
- * \note
- * \warning
- */
-
-#include "PHY/TOOLS/time_meas.h"
-
-/*ldpc_encoder.c*/
-int encode_parity_check_part_orig(unsigned char *c,unsigned char *d, short BG,short Zc,short Kb,short block_length);
-
-/*ldpc_encoder2.c*/
-void encode_parity_check_part_optim(uint8_t *c,uint8_t *d, short BG,short Zc,short Kb);
-int ldpc_encoder_optim(unsigned char *test_input,unsigned char *channel_input,int Zc,int Kb,short block_length,short BG,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput);
-int ldpc_encoder_optim_8seg(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length,short BG,int n_segments,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput);
-int ldpc_encoder_optim_8seg_multi(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, int n_segments,unsigned int macro_num, time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput);
-
-/*ldpc_generate_coefficient.c*/
-int ldpc_encoder_orig(unsigned char *test_input,unsigned char *channel_input,int Zc,int Kb,short block_length,short BG,unsigned char gen_code);
-
-/*
-int encode_parity_check_part(unsigned char *c,unsigned char *d, short BG,short Zc,short Kb);
-int encode_parity_check_part_orig(unsigned char *c,unsigned char *d, short BG,short Zc,short Kb,short block_length);
-int ldpc_encoder(unsigned char *test_input,unsigned char *channel_input,short block_length, double rate);
-int ldpc_encoder_orig(unsigned char *test_input,unsigned char *channel_input,short block_length,int nom_rate,int denom_rate,unsigned char gen_code);
-int ldpc_encoder_multi_segment(unsigned char **test_input,unsigned char **channel_input,short block_length,double rate,uint8_t n_segments);
-int ldpc_encoder_optim(unsigned char *test_input,unsigned char *channel_input,short block_length,int nom_rate,int denom_rate,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput);
-int ldpc_encoder_optim_8seg(unsigned char **test_input,unsigned char **channel_input,short block_length,int nom_rate,int denom_rate,int n_segments,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput);
-*/
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encode_parity_check.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encode_parity_check.c
new file mode 100644
index 0000000000000000000000000000000000000000..738fd49b7d36b1892aa3868a5f6d0c65baf6bbb3
--- /dev/null
+++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encode_parity_check.c
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+/*!\file ldpc_encode_parity_check.c
+ * \brief Parity check function used by ldpc encoders
+ * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom)
+ * \email openair_tech@eurecom.fr
+ * \date 27-03-2018
+ * \version 1.0
+ * \note
+ * \warning
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <types.h>
+#include "assertions.h"
+#include "common/utils/LOG/log.h"
+
+
+//#define DEBUG_LDPC
+
+#include "ldpc384_byte.c"
+#include "ldpc352_byte.c"
+#include "ldpc320_byte.c"
+#include "ldpc288_byte.c"
+#include "ldpc256_byte.c"
+#include "ldpc240_byte.c"
+#include "ldpc224_byte.c"
+#include "ldpc208_byte.c"
+#include "ldpc192_byte.c"
+#include "ldpc176_byte.c"
+#include "ldpc_BG2_Zc384_byte.c"
+#include "ldpc_BG2_Zc352_byte.c"
+#include "ldpc_BG2_Zc320_byte.c"
+#include "ldpc_BG2_Zc288_byte.c"
+#include "ldpc_BG2_Zc256_byte.c"
+#include "ldpc_BG2_Zc240_byte.c"
+#include "ldpc_BG2_Zc224_byte.c"
+#include "ldpc_BG2_Zc208_byte.c"
+#include "ldpc_BG2_Zc192_byte.c"
+#include "ldpc_BG2_Zc176_byte.c"
+#include "ldpc_BG2_Zc160_byte.c"
+#include "ldpc_BG2_Zc144_byte.c"
+#include "ldpc_BG2_Zc128_byte.c"
+#include "ldpc_BG2_Zc120_byte.c"
+#include "ldpc_BG2_Zc112_byte.c"
+#include "ldpc_BG2_Zc104_byte.c"
+#include "ldpc_BG2_Zc96_byte.c"
+#include "ldpc_BG2_Zc88_byte.c"
+#include "ldpc_BG2_Zc80_byte.c"
+#include "ldpc_BG2_Zc72_byte.c"
+
+
+
+static inline void encode_parity_check_part_optim(uint8_t *c,uint8_t *d, short BG,short Zc,short Kb)
+{
+
+  if (BG==1)
+  {
+    switch (Zc)
+    {
+    case 2: break;
+    case 3: break;
+    case 4: break;
+    case 5: break;
+    case 6: break;
+    case 7: break;
+    case 8: break;
+    case 9: break;
+    case 10: break;
+    case 11: break;
+    case 12: break;
+    case 13: break;
+    case 14: break;
+    case 15: break;
+    case 16: break;
+    case 18: break;
+    case 20: break;
+    case 22: break;
+    case 24: break;      
+    case 26: break;
+    case 28: break;
+    case 30: break;
+    case 32: break;
+    case 36: break;
+    case 40: break;
+    case 44: break;
+    case 48: break;
+    case 52: break;
+    case 56: break;
+    case 60: break;
+    case 64: break;
+    case 72: break;
+    case 80: break;   
+    case 88: break;   
+    case 96: break;
+    case 104: break;
+    case 112: break;
+    case 120: break;
+    case 128: break;
+    case 144: break;
+    case 160: break;
+    case 176: ldpc176_byte(c,d); break;
+    case 192: ldpc192_byte(c,d); break;
+    case 208: ldpc208_byte(c,d); break;
+    case 224: ldpc224_byte(c,d); break;
+    case 240: ldpc240_byte(c,d); break;
+    case 256: ldpc256_byte(c,d); break;
+    case 288: ldpc288_byte(c,d); break;
+    case 320: ldpc320_byte(c,d); break;
+    case 352: ldpc352_byte(c,d); break;
+    case 384: ldpc384_byte(c,d); break;
+    default: AssertFatal(0,"BG %d Zc %d is not supported yet\n",BG,Zc); break;
+    }
+  }
+  else if (BG==2) {
+    switch (Zc)
+    {
+    case 2: break;
+    case 3: break;
+    case 4: break;
+    case 5: break;
+    case 6: break;
+    case 7: break;
+    case 8: break;
+    case 9: break;
+    case 10: break;
+    case 11: break;
+    case 12: break;
+    case 13: break;
+    case 14: break;
+    case 15: break;
+    case 16: break;
+    case 18: break;
+    case 20: break;
+    case 22: break;
+    case 24: break;      
+    case 26: break;
+    case 28: break;
+    case 30: break;
+    case 32: break;
+    case 36: break;
+    case 40: break;
+    case 44: break;
+    case 48: break;
+    case 52: break;
+    case 56: break;
+    case 60: break;
+    case 64: break;
+    case 72: ldpc_BG2_Zc72_byte(c,d); break;
+    case 80: ldpc_BG2_Zc80_byte(c,d); break;   
+    case 88: ldpc_BG2_Zc88_byte(c,d); break;   
+    case 96: ldpc_BG2_Zc96_byte(c,d); break;
+    case 104: ldpc_BG2_Zc104_byte(c,d); break;
+    case 112: ldpc_BG2_Zc112_byte(c,d); break;
+    case 120: ldpc_BG2_Zc120_byte(c,d); break;
+    case 128: ldpc_BG2_Zc128_byte(c,d); break;
+    case 144: ldpc_BG2_Zc144_byte(c,d); break;
+    case 160: ldpc_BG2_Zc160_byte(c,d); break;
+    case 176: ldpc_BG2_Zc176_byte(c,d); break;
+    case 192: ldpc_BG2_Zc192_byte(c,d); break;
+    case 208: ldpc_BG2_Zc208_byte(c,d); break;
+    case 224: ldpc_BG2_Zc224_byte(c,d); break;
+    case 240: ldpc_BG2_Zc240_byte(c,d); break;
+    case 256: ldpc_BG2_Zc256_byte(c,d); break;
+    case 288: ldpc_BG2_Zc288_byte(c,d); break;
+    case 320: ldpc_BG2_Zc320_byte(c,d); break;
+    case 352: ldpc_BG2_Zc352_byte(c,d); break;
+    case 384: ldpc_BG2_Zc384_byte(c,d); break;
+    default: AssertFatal(0,"BG %d Zc %d is not supported yet\n",BG,Zc); break;
+    }
+  }
+  else {
+    AssertFatal(0,"BG %d is not supported yet\n",BG);
+  } 
+
+}
+
+
+
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c
index 6ded22d8cab5222811a474dcb4b34c71c4bed435..76f92574bad3498c416a6318c1f84cbdc8ea5378 100644
--- a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c
+++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c
@@ -37,77 +37,247 @@
 #include <string.h>
 #include <types.h>
 #include "defs.h"
+#include "assertions.h"
+#include "openair1/PHY/CODING/nrLDPC_defs.h"
+#include "ldpc_generate_coefficient.c"
 
-short *choose_generator_matrix(short BG,short Zc);
-extern short no_shift_values_BG1[1012],pointer_shift_values_BG1[1012],no_shift_values_BG2[2109],pointer_shift_values_BG2[2019];
 
-int encode_parity_check_part_orig(unsigned char *c,unsigned char *d, short BG,short Zc,short Kb,short block_length)
+int ldpc_encoder_orig(unsigned char *test_input,unsigned char *channel_input,int Zc,int Kb,short block_length, short BG,unsigned char gen_code)
 {
-  short *Gen_shift_values=choose_generator_matrix(BG,Zc);
-  short *no_shift_values, *pointer_shift_values;
-  int no_punctured_columns;
-  short nrows,ncols,rate=3;
-  int i1,i2,i3,i4,i5,temp_prime;
+  unsigned char c[22*384]; //padded input, unpacked, max size
+  unsigned char d[68*384]; //coded output, unpacked, max size
   unsigned char channel_temp,temp;
+  short *Gen_shift_values, *no_shift_values, *pointer_shift_values;
 
+  short nrows = 46;//parity check bits
+  short ncols = 22;//info bits
+
+
+  int i,i1,i2,i3,i4,i5,temp_prime,var;
+  int no_punctured_columns,removed_bit,rate=3;
+  int nind=0;
+  int indlist[1000];
+  int indlist2[1000];
+
+  //determine number of bits in codeword
+  //if (block_length>3840)
+     if (BG==1)
+       {
+         nrows=46; //parity check bits
+         ncols=22; //info bits
+         rate=3;
+       }
+       //else if (block_length<=3840)
+      else if	(BG==2)
+       {
+         //BG=2;
+         nrows=42; //parity check bits
+         ncols=10; // info bits
+         rate=5;
+         }
+
+  Gen_shift_values=choose_generator_matrix(BG,Zc);
+  if (Gen_shift_values==NULL) {
+    printf("ldpc_encoder_orig: could not find generator matrix\n");
+    return(-1);
+  }
+
+  //printf("ldpc_encoder_orig: BG %d, Zc %d, Kb %d\n",BG, Zc, Kb);
+
+  // load base graph of generator matrix
   if (BG==1)
   {
     no_shift_values=(short *) no_shift_values_BG1;
     pointer_shift_values=(short *) pointer_shift_values_BG1;
-      nrows=46; //parity check bits
-      ncols=22; //info bits
-      rate=3;
   }
   else if (BG==2)
   {
     no_shift_values=(short *) no_shift_values_BG2;
     pointer_shift_values=(short *) pointer_shift_values_BG2;
-      nrows=42; //parity check bits
-      ncols=10; //info bits
-      rate=5;
   }
   else {
-    printf("problem with BG\n");
-    return(-1);
+    AssertFatal(0,"BG %d is not supported yet\n",BG);
   }
-
-
+  
   no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
+  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(block_length*rate);
+  //printf("%d\n",no_punctured_columns);
+  //printf("%d\n",removed_bit);
+  // unpack input
+  memset(c,0,sizeof(unsigned char) * ncols * Zc);
+  memset(d,0,sizeof(unsigned char) * nrows * Zc);
+
+  for (i=0; i<block_length; i++)
+  {
+    //c[i] = test_input[i/8]<<(i%8);
+    //c[i]=c[i]>>7&1;
+    c[i]=(test_input[i/8]&(128>>(i&7)))>>(7-(i&7));
+  }
 
-  //printf("no_punctured_columns = %d\n",no_punctured_columns);
+  // parity check part
 
-  for (i2=0; i2 < Zc; i2++)
+  if (gen_code==1)
   {
-    //t=Kb*Zc+i2;
+    char fname[100];
+    sprintf(fname,"ldpc_BG%d_Zc%d_byte.c",BG,Zc);
+    FILE *fd=fopen(fname,"w");
+    AssertFatal(fd!=NULL,"cannot open %s\n",fname);
+    sprintf(fname,"ldpc_BG%d_Zc%d_16bit.c",BG,Zc);
+    FILE *fd2=fopen(fname,"w");
+    AssertFatal(fd2!=NULL,"cannot open %s\n",fname);
 
-    //rotate matrix here
-    for (i5=0; i5 < Kb; i5++)
-    {
-      temp = c[i5*Zc];
-      memmove(&c[i5*Zc], &c[i5*Zc+1], (Zc-1)*sizeof(unsigned char));
-      c[i5*Zc+Zc-1] = temp;
+    int shift;
+    char data_type[100];
+    char xor_command[100];
+    int mask;
+
+
+
+
+    fprintf(fd,"#include \"PHY/sse_intrin.h\"\n");
+    fprintf(fd2,"#include \"PHY/sse_intrin.h\"\n");
+
+    if ((Zc&31)==0) {
+      shift=5; // AVX2 - 256-bit SIMD
+      mask=31;
+      strcpy(data_type,"__m256i");
+      strcpy(xor_command,"_mm256_xor_si256");
     }
+    else if ((Zc&15)==0) {
+      shift=4; // SSE4 - 128-bit SIMD
+      mask=15;
+      strcpy(data_type,"__m128i");
+      strcpy(xor_command,"_mm_xor_si128");
 
-    // calculate each row in base graph
-    for (i1=0; i1 < nrows-no_punctured_columns; i1++)
+    }
+    else if ((Zc&7)==0) {
+      shift=3; // MMX  - 64-bit SIMD
+      mask=7;
+      strcpy(data_type,"__m64");
+      strcpy(xor_command,"_mm_xor_si64"); 
+    }
+    else {
+      shift=0;                 // no SIMD
+      mask=0;
+      strcpy(data_type,"uint8_t");
+      strcpy(xor_command,"scalar_xor");
+      fprintf(fd,"#define scalar_xor(a,b) ((a)^(b))\n");
+      fprintf(fd2,"#define scalar_xor(a,b) ((a)^(b))\n");
+    }
+    fprintf(fd,"// generated code for Zc=%d, byte encoding\n",Zc);
+    fprintf(fd2,"// generated code for Zc=%d, 16bit encoding\n",Zc);
+    fprintf(fd,"static inline void ldpc_BG%d_Zc%d_byte(uint8_t *c,uint8_t *d) {\n",BG,Zc);
+    fprintf(fd2,"static inline void ldpc_BG%d_Zc%d_16bit(uint16_t *c,uint16_t *d) {\n",BG,Zc);
+    fprintf(fd,"  %s *csimd=(%s *)c,*dsimd=(%s *)d;\n\n",data_type,data_type,data_type);
+    fprintf(fd2,"  %s *csimd=(%s *)c,*dsimd=(%s *)d;\n\n",data_type,data_type,data_type);
+    fprintf(fd,"  %s *c2,*d2;\n\n",data_type);
+    fprintf(fd2,"  %s *c2,*d2;\n\n",data_type);
+    fprintf(fd,"  int i2;\n");
+    fprintf(fd2,"  int i2;\n");
+    fprintf(fd,"  for (i2=0; i2<%d; i2++) {\n",Zc>>shift);
+    if (shift > 0)
+      fprintf(fd2,"  for (i2=0; i2<%d; i2++) {\n",Zc>>(shift-1));
+    for (i2=0; i2 < 1; i2++)
     {
-      channel_temp=0;
-      for (i3=0; i3 < Kb; i3++)
+      //t=Kb*Zc+i2;
+    
+      // calculate each row in base graph
+     
+
+      fprintf(fd,"     c2=&csimd[i2];\n");
+      fprintf(fd,"     d2=&dsimd[i2];\n");
+      fprintf(fd2,"     c2=&csimd[i2];\n");
+      fprintf(fd2,"     d2=&dsimd[i2];\n");
+
+      for (i1=0; i1 < nrows; i1++)
+
       {
-        temp_prime=i1 * ncols + i3;
+        channel_temp=0;
+        fprintf(fd,"\n//row: %d\n",i1);
+        fprintf(fd2,"\n//row: %d\n",i1);
+	fprintf(fd,"     d2[%d]=",(Zc*i1)>>shift);
+	fprintf(fd2,"     d2[%d]=",(Zc*i1)>>(shift-1));
+
+        nind=0;
 
-        for (i4=0; i4 < no_shift_values[temp_prime]; i4++)
+        for (i3=0; i3 < ncols; i3++)
         {
-          channel_temp = channel_temp ^ c[ i3*Zc + Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ] ];
+          temp_prime=i1 * ncols + i3;
+
+
+	  for (i4=0; i4 < no_shift_values[temp_prime]; i4++)
+	    {
+	          
+	      var=(int)((i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc)/Zc);
+	      int index =var*2*Zc + (i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc) % Zc;
+	      
+	      indlist[nind] = ((index&mask)*((2*Zc)>>shift)*Kb)+(index>>shift);
+	      indlist2[nind++] = ((index&(mask>>1))*((2*Zc)>>(shift-1))*Kb)+(index>>(shift-1));
+	      
+	    }
+	  
+
         }
+	for (i4=0;i4<nind-1;i4++) {
+	  fprintf(fd,"%s(c2[%d],",xor_command,indlist[i4]);
+	  fprintf(fd2,"%s(c2[%d],",xor_command,indlist2[i4]);
+	}
+	fprintf(fd,"c2[%d]",indlist[i4]);
+	fprintf(fd2,"c2[%d]",indlist2[i4]);
+	for (i4=0;i4<nind-1;i4++) { fprintf(fd,")"); fprintf(fd2,")"); }
+	fprintf(fd,";\n");
+	fprintf(fd2,";\n");
+
       }
-      d[i2+i1*Zc]=channel_temp;
-      //channel_input[t+i1*Zc]=channel_temp;
+      fprintf(fd,"  }\n}\n");
+      fprintf(fd2,"  }\n}\n");
     }
+    fclose(fd);
+    fclose(fd2);
   }
-  return(0);
-}
+  else if(gen_code==0)
+  {
+    for (i2=0; i2 < Zc; i2++)
+    {
+      //t=Kb*Zc+i2;
 
+      //rotate matrix here
+      for (i5=0; i5 < Kb; i5++)
+      {
+        temp = c[i5*Zc];
+        memmove(&c[i5*Zc], &c[i5*Zc+1], (Zc-1)*sizeof(unsigned char));
+        c[i5*Zc+Zc-1] = temp;
+      }
 
+      // calculate each row in base graph
+      for (i1=0; i1 < nrows-no_punctured_columns; i1++)
+      {
+        channel_temp=0;
+
+        for (i3=0; i3 < Kb; i3++)
+        {
+          temp_prime=i1 * ncols + i3;
+
+          for (i4=0; i4 < no_shift_values[temp_prime]; i4++)
+          {
+            channel_temp = channel_temp ^ c[ i3*Zc + Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ] ];
+          }
+        }
+
+        d[i2+i1*Zc]=channel_temp;
+        //channel_input[t+i1*Zc]=channel_temp;
+      }
+    }
+  }
+
+  // information part and puncture columns
+  memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
+  memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
+  //memcpy(channel_input,c,Kb*Zc*sizeof(unsigned char));
+  return 0;
+}
 
 
+int nrLDPC_encod(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, encoder_implemparams_t *impp) {
+  return ldpc_encoder_orig(test_input[0],channel_input[0],Zc,Kb,block_length,BG,impp->gen_code);
+}
\ No newline at end of file
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder2.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder2.c
deleted file mode 100644
index ef207b6cdcd683dbc18c6a0f6541033635312315..0000000000000000000000000000000000000000
--- a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder2.c
+++ /dev/null
@@ -1,667 +0,0 @@
-/*
- * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The OpenAirInterface Software Alliance licenses this file to You under
- * the OAI Public License, Version 1.1  (the "License"); you may not use this file
- * except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.openairinterface.org/?page_id=698
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *-------------------------------------------------------------------------------
- * For more information about the OpenAirInterface (OAI) Software Alliance:
- *      contact@openairinterface.org
- */
-
-/*!\file ldpc_encoder2.c
- * \brief Defines the optimized LDPC encoder
- * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom)
- * \email openair_tech@eurecom.fr
- * \date 27-03-2018
- * \version 1.0
- * \note
- * \warning
- */
-
-#include <stdlib.h>
-#include <math.h>
-#include <stdio.h>
-#include <string.h>
-#include <types.h>
-#include "assertions.h"
-#include "common/utils/LOG/log.h"
-#include "PHY/TOOLS/time_meas.h"
-#include "defs.h"
-
-//#define DEBUG_LDPC
-
-#include "ldpc384_byte.c"
-#include "ldpc352_byte.c"
-#include "ldpc320_byte.c"
-#include "ldpc288_byte.c"
-#include "ldpc256_byte.c"
-#include "ldpc240_byte.c"
-#include "ldpc224_byte.c"
-#include "ldpc208_byte.c"
-#include "ldpc192_byte.c"
-#include "ldpc176_byte.c"
-#include "ldpc_BG2_Zc384_byte.c"
-#include "ldpc_BG2_Zc352_byte.c"
-#include "ldpc_BG2_Zc320_byte.c"
-#include "ldpc_BG2_Zc288_byte.c"
-#include "ldpc_BG2_Zc256_byte.c"
-#include "ldpc_BG2_Zc240_byte.c"
-#include "ldpc_BG2_Zc224_byte.c"
-#include "ldpc_BG2_Zc208_byte.c"
-#include "ldpc_BG2_Zc192_byte.c"
-#include "ldpc_BG2_Zc176_byte.c"
-#include "ldpc_BG2_Zc160_byte.c"
-#include "ldpc_BG2_Zc144_byte.c"
-#include "ldpc_BG2_Zc128_byte.c"
-#include "ldpc_BG2_Zc120_byte.c"
-#include "ldpc_BG2_Zc112_byte.c"
-#include "ldpc_BG2_Zc104_byte.c"
-#include "ldpc_BG2_Zc96_byte.c"
-#include "ldpc_BG2_Zc88_byte.c"
-#include "ldpc_BG2_Zc80_byte.c"
-#include "ldpc_BG2_Zc72_byte.c"
-
-
-
-void encode_parity_check_part_optim(uint8_t *c,uint8_t *d, short BG,short Zc,short Kb)
-{
-
-  if (BG==1)
-  {
-    switch (Zc)
-    {
-    case 2: break;
-    case 3: break;
-    case 4: break;
-    case 5: break;
-    case 6: break;
-    case 7: break;
-    case 8: break;
-    case 9: break;
-    case 10: break;
-    case 11: break;
-    case 12: break;
-    case 13: break;
-    case 14: break;
-    case 15: break;
-    case 16: break;
-    case 18: break;
-    case 20: break;
-    case 22: break;
-    case 24: break;      
-    case 26: break;
-    case 28: break;
-    case 30: break;
-    case 32: break;
-    case 36: break;
-    case 40: break;
-    case 44: break;
-    case 48: break;
-    case 52: break;
-    case 56: break;
-    case 60: break;
-    case 64: break;
-    case 72: break;
-    case 80: break;   
-    case 88: break;   
-    case 96: break;
-    case 104: break;
-    case 112: break;
-    case 120: break;
-    case 128: break;
-    case 144: break;
-    case 160: break;
-    case 176: ldpc176_byte(c,d); break;
-    case 192: ldpc192_byte(c,d); break;
-    case 208: ldpc208_byte(c,d); break;
-    case 224: ldpc224_byte(c,d); break;
-    case 240: ldpc240_byte(c,d); break;
-    case 256: ldpc256_byte(c,d); break;
-    case 288: ldpc288_byte(c,d); break;
-    case 320: ldpc320_byte(c,d); break;
-    case 352: ldpc352_byte(c,d); break;
-    case 384: ldpc384_byte(c,d); break;
-    default: AssertFatal(0,"BG %d Zc %d is not supported yet\n",BG,Zc); break;
-    }
-  }
-  else if (BG==2) {
-    switch (Zc)
-    {
-    case 2: break;
-    case 3: break;
-    case 4: break;
-    case 5: break;
-    case 6: break;
-    case 7: break;
-    case 8: break;
-    case 9: break;
-    case 10: break;
-    case 11: break;
-    case 12: break;
-    case 13: break;
-    case 14: break;
-    case 15: break;
-    case 16: break;
-    case 18: break;
-    case 20: break;
-    case 22: break;
-    case 24: break;      
-    case 26: break;
-    case 28: break;
-    case 30: break;
-    case 32: break;
-    case 36: break;
-    case 40: break;
-    case 44: break;
-    case 48: break;
-    case 52: break;
-    case 56: break;
-    case 60: break;
-    case 64: break;
-    case 72: ldpc_BG2_Zc72_byte(c,d); break;
-    case 80: ldpc_BG2_Zc80_byte(c,d); break;   
-    case 88: ldpc_BG2_Zc88_byte(c,d); break;   
-    case 96: ldpc_BG2_Zc96_byte(c,d); break;
-    case 104: ldpc_BG2_Zc104_byte(c,d); break;
-    case 112: ldpc_BG2_Zc112_byte(c,d); break;
-    case 120: ldpc_BG2_Zc120_byte(c,d); break;
-    case 128: ldpc_BG2_Zc128_byte(c,d); break;
-    case 144: ldpc_BG2_Zc144_byte(c,d); break;
-    case 160: ldpc_BG2_Zc160_byte(c,d); break;
-    case 176: ldpc_BG2_Zc176_byte(c,d); break;
-    case 192: ldpc_BG2_Zc192_byte(c,d); break;
-    case 208: ldpc_BG2_Zc208_byte(c,d); break;
-    case 224: ldpc_BG2_Zc224_byte(c,d); break;
-    case 240: ldpc_BG2_Zc240_byte(c,d); break;
-    case 256: ldpc_BG2_Zc256_byte(c,d); break;
-    case 288: ldpc_BG2_Zc288_byte(c,d); break;
-    case 320: ldpc_BG2_Zc320_byte(c,d); break;
-    case 352: ldpc_BG2_Zc352_byte(c,d); break;
-    case 384: ldpc_BG2_Zc384_byte(c,d); break;
-    default: AssertFatal(0,"BG %d Zc %d is not supported yet\n",BG,Zc); break;
-    }
-  }
-  else {
-    AssertFatal(0,"BG %d is not supported yet\n",BG);
-  } 
-
-}
-
-
-int ldpc_encoder_optim(unsigned char *test_input,unsigned char *channel_input,int Zc,int Kb,short block_length,short BG,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput)
-{
-
-  short nrows=0,ncols=0;
-  int i,i1,rate=3;
-  int no_punctured_columns,removed_bit;
-
-  int simd_size;
-
-  //determine number of bits in codeword
-   //if (block_length>3840)
-   if (BG==1)
-     {
-       //BG=1;
-       nrows=46; //parity check bits
-       ncols=22; //info bits
-       rate=3;
-     }
-     //else if (block_length<=3840)
-    else if	(BG==2)
-     {
-       //BG=2;
-       nrows=42; //parity check bits
-       ncols=10; // info bits
-       rate=5;
-
-       }
-
-
-#ifdef DEBUG_LDPC
-  LOG_D(PHY,"ldpc_encoder_optim_8seg: BG %d, Zc %d, Kb %d, block_length %d\n",BG,Zc,Kb,block_length);
-  LOG_D(PHY,"ldpc_encoder_optim_8seg: PDU %x %x %x %x\n",test_input[0],test_input[1],test_input[2],test_input[3]);
-#endif
-
-  if ((Zc&31) > 0) simd_size = 16;
-  else simd_size = 32;
-
-  unsigned char c[22*Zc] __attribute__((aligned(32))); //padded input, unpacked, max size
-  unsigned char d[46*Zc] __attribute__((aligned(32))); //coded parity part output, unpacked, max size
-
-  unsigned char c_extension[2*22*Zc*simd_size] __attribute__((aligned(32)));      //double size matrix of c
-
-  // calculate number of punctured bits
-  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
-  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate);
-  // printf("%d\n",no_punctured_columns);
-  // printf("%d\n",removed_bit);
-  // unpack input
-  memset(c,0,sizeof(unsigned char) * ncols * Zc);
-  memset(d,0,sizeof(unsigned char) * nrows * Zc);
-
-  if(tinput != NULL) start_meas(tinput);
-  for (i=0; i<block_length; i++) {
-    c[i] = (test_input[i/8]&(128>>(i&7)))>>(7-(i&7));
-      //printf("c(%d,%d)=%d\n",j,i,temp);
-    }
-
-  if(tinput != NULL) stop_meas(tinput);
-
-  if ((BG==1 && Zc>176) || (BG==2 && Zc>64)) { 
-    // extend matrix
-    if(tprep != NULL) start_meas(tprep);
-    for (i1=0; i1 < ncols; i1++)
-      {
-	memcpy(&c_extension[2*i1*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
-	memcpy(&c_extension[(2*i1+1)*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
-      }
-    for (i1=1;i1<simd_size;i1++) {
-      memcpy(&c_extension[(2*ncols*Zc*i1)], &c_extension[i1], (2*ncols*Zc*sizeof(unsigned char))-i1);
-      //    memset(&c_extension[(2*ncols*Zc*i1)],0,i1);
-      /*
-	printf("shift %d: ",i1);
-	for (int j=0;j<64;j++) printf("%d ",c_extension[(2*ncols*Zc*i1)+j]);
-	printf("\n");
-      */
-    }
-    if(tprep != NULL) stop_meas(tprep);
-    //parity check part
-    if(tparity != NULL) start_meas(tparity);
-    encode_parity_check_part_optim(c_extension, d, BG, Zc, Kb);
-    if(tparity != NULL) stop_meas(tparity);
-  }
-  else {
-    if (encode_parity_check_part_orig(c, d, BG, Zc, Kb, block_length)!=0) {
-      printf("Problem with encoder\n");
-      return(-1);
-    }
-  }
-  if(toutput != NULL) start_meas(toutput);
-  // information part and puncture columns
-  memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
-  memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
-
-  if(toutput != NULL) stop_meas(toutput);
-  return 0;
-}
-
-int ldpc_encoder_optim_8seg(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length,short BG,int n_segments,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput)
-{
-
-  short nrows=0,ncols=0;
-  int i,i1,j,rate=3;
-  int no_punctured_columns,removed_bit;
-  char temp;
-  int simd_size;
-
-#ifdef __AVX2__
-  __m256i shufmask = _mm256_set_epi64x(0x0303030303030303, 0x0202020202020202,0x0101010101010101, 0x0000000000000000);
-  __m256i andmask  = _mm256_set1_epi64x(0x0102040810204080);  // every 8 bits -> 8 bytes, pattern repeats.
-  __m256i zero256   = _mm256_setzero_si256();
-  __m256i masks[8];
-  register __m256i c256;
-  masks[0] = _mm256_set1_epi8(0x1);
-  masks[1] = _mm256_set1_epi8(0x2);
-  masks[2] = _mm256_set1_epi8(0x4);
-  masks[3] = _mm256_set1_epi8(0x8);
-  masks[4] = _mm256_set1_epi8(0x10);
-  masks[5] = _mm256_set1_epi8(0x20);
-  masks[6] = _mm256_set1_epi8(0x40);
-  masks[7] = _mm256_set1_epi8(0x80);
-#endif
-
-  AssertFatal(n_segments>0&&n_segments<=8,"0 < n_segments %d <= 8\n",n_segments);
-
-  //determine number of bits in codeword
-  //if (block_length>3840)
-  if (BG==1)
-    {
-      nrows=46; //parity check bits
-      ncols=22; //info bits
-      rate=3;
-    }
-    //else if (block_length<=3840)
-   else if	(BG==2)
-    {
-      //BG=2;
-      nrows=42; //parity check bits
-      ncols=10; // info bits
-      rate=5;
-
-      }
-
-#ifdef DEBUG_LDPC
-  LOG_D(PHY,"ldpc_encoder_optim_8seg: BG %d, Zc %d, Kb %d, block_length %d, segments %d\n",BG,Zc,Kb,block_length,n_segments);
-  LOG_D(PHY,"ldpc_encoder_optim_8seg: PDU (seg 0) %x %x %x %x\n",test_input[0][0],test_input[0][1],test_input[0][2],test_input[0][3]);
-#endif
-
-  AssertFatal(Zc>0,"no valid Zc found for block length %d\n",block_length);
-
-  if ((Zc&31) > 0) simd_size = 16;
-  else          simd_size = 32;
-
-  unsigned char c[22*Zc] __attribute__((aligned(32))); //padded input, unpacked, max size
-  unsigned char d[46*Zc] __attribute__((aligned(32))); //coded parity part output, unpacked, max size
-
-  unsigned char c_extension[2*22*Zc*simd_size] __attribute__((aligned(32)));      //double size matrix of c
-
-  // calculate number of punctured bits
-  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
-  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate);
-  // printf("%d\n",no_punctured_columns);
-  // printf("%d\n",removed_bit);
-  // unpack input
-  memset(c,0,sizeof(unsigned char) * ncols * Zc);
-  memset(d,0,sizeof(unsigned char) * nrows * Zc);
-
-  if(tinput != NULL) start_meas(tinput);
-#if 0
-  for (i=0; i<block_length; i++) {
-    for (j=0; j<n_segments; j++) {
-
-      temp = (test_input[j][i/8]&(128>>(i&7)))>>(7-(i&7));
-      //printf("c(%d,%d)=%d\n",j,i,temp);
-      c[i] |= (temp << j);
-    }
-  }
-#else
-#ifdef __AVX2__
-  for (i=0; i<block_length>>5; i++) {
-    c256 = _mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[0])[i]), shufmask),andmask),zero256),masks[0]);
-    for (j=1; j<n_segments; j++) {
-      c256 = _mm256_or_si256(_mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[j])[i]), shufmask),andmask),zero256),masks[j]),c256);
-    }
-    ((__m256i *)c)[i] = c256;
-  }
-
-  for (i=(block_length>>5)<<5;i<block_length;i++) {
-    for (j=0; j<n_segments; j++) {
-
-      temp = (test_input[j][i/8]&(128>>(i&7)))>>(7-(i&7));
-      //printf("c(%d,%d)=%d\n",j,i,temp);
-      c[i] |= (temp << j);
-    }
-  }
-#else
-  AssertFatal(1==0,"Need AVX2 for this\n");
-#endif
-#endif
-
-  if(tinput != NULL) stop_meas(tinput);
-
-  if ((BG==1 && Zc>176) || (BG==2 && Zc>64)) { 
-    // extend matrix
-    if(tprep != NULL) start_meas(tprep);
-    for (i1=0; i1 < ncols; i1++)
-      {
-	memcpy(&c_extension[2*i1*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
-	memcpy(&c_extension[(2*i1+1)*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
-      }
-    for (i1=1;i1<simd_size;i1++) {
-      memcpy(&c_extension[(2*ncols*Zc*i1)], &c_extension[i1], (2*ncols*Zc*sizeof(unsigned char))-i1);
-      //    memset(&c_extension[(2*ncols*Zc*i1)],0,i1);
-      /*
-	printf("shift %d: ",i1);
-	for (int j=0;j<64;j++) printf("%d ",c_extension[(2*ncols*Zc*i1)+j]);
-	printf("\n");
-      */
-    }
-    if(tprep != NULL) stop_meas(tprep);
-    //parity check part
-    if(tparity != NULL) start_meas(tparity);
-    encode_parity_check_part_optim(c_extension, d, BG, Zc, Kb);
-    if(tparity != NULL) stop_meas(tparity);
-  }
-  else {
-    if (encode_parity_check_part_orig(c, d, BG, Zc, Kb, block_length)!=0) {
-      printf("Problem with encoder\n");
-      return(-1);
-    }
-  }
-  if(toutput != NULL) start_meas(toutput);
-  // information part and puncture columns
-  /*
-  memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
-  memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
-  */
-#ifdef __AVX2__
-  if ((((2*Zc)&31) == 0) && (((block_length-(2*Zc))&31) == 0)) {
-    //AssertFatal(((2*Zc)&31) == 0,"2*Zc needs to be a multiple of 32 for now\n");
-    //AssertFatal(((block_length-(2*Zc))&31) == 0,"block_length-(2*Zc) needs to be a multiple of 32 for now\n");
-    uint32_t l1 = (block_length-(2*Zc))>>5;
-    uint32_t l2 = ((nrows-no_punctured_columns) * Zc-removed_bit)>>5;
-    __m256i *c256p = (__m256i *)&c[2*Zc];
-    __m256i *d256p = (__m256i *)&d[0];
-    //  if (((block_length-(2*Zc))&31)>0) l1++;
-    
-    for (i=0;i<l1;i++)
-      for (j=0;j<n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(c256p[i],j),masks[0]);
-    
-    //  if ((((nrows-no_punctured_columns) * Zc-removed_bit)&31)>0) l2++;
-    
-    for (i1=0;i1<l2;i1++,i++)
-      for (j=0;j<n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(d256p[i1],j),masks[0]);
-  }
-  else {
-#ifdef DEBUG_LDPC
-  LOG_W(PHY,"using non-optimized version\n");
-#endif
-    // do non-SIMD version
-    for (i=0;i<(block_length-2*Zc);i++) 
-      for (j=0; j<n_segments; j++)
-	channel_input[j][i] = (c[2*Zc+i]>>j)&1;
-    for (i=0;i<((nrows-no_punctured_columns) * Zc-removed_bit);i++)
-      for (j=0; j<n_segments; j++)
-	channel_input[j][block_length-2*Zc+i] = (d[i]>>j)&1;
-    }
-
-#else
-    AssertFatal(1==0,"Need AVX2 for now\n");
-#endif
-
-  if(toutput != NULL) stop_meas(toutput);
-  return 0;
-}
-
-int ldpc_encoder_optim_8seg_multi(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, int n_segments,unsigned int macro_num, time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput)
-{
-
-  short nrows=0,ncols=0;
-  int i,i1,j,rate=3;
-  int no_punctured_columns,removed_bit;
-  //Table of possible lifting sizes
-  char temp;
-  int simd_size;
-  unsigned int macro_segment, macro_segment_end;
-
-  
-  macro_segment = 8*macro_num;
-  // macro_segment_end = (n_segments > 8*(macro_num+1)) ? 8*(macro_num+1) : n_segments;
-  macro_segment_end = macro_segment + (n_segments > 8 ? 8 : n_segments);
-  ///printf("macro_segment: %d\n", macro_segment);
-  ///printf("macro_segment_end: %d\n", macro_segment_end );
-
-#ifdef __AVX2__
-  __m256i shufmask = _mm256_set_epi64x(0x0303030303030303, 0x0202020202020202,0x0101010101010101, 0x0000000000000000);
-  __m256i andmask  = _mm256_set1_epi64x(0x0102040810204080);  // every 8 bits -> 8 bytes, pattern repeats.
-  __m256i zero256   = _mm256_setzero_si256();
-  __m256i masks[8];
-  register __m256i c256;
-  masks[0] = _mm256_set1_epi8(0x1);
-  masks[1] = _mm256_set1_epi8(0x2);
-  masks[2] = _mm256_set1_epi8(0x4);
-  masks[3] = _mm256_set1_epi8(0x8);
-  masks[4] = _mm256_set1_epi8(0x10);
-  masks[5] = _mm256_set1_epi8(0x20);
-  masks[6] = _mm256_set1_epi8(0x40);
-  masks[7] = _mm256_set1_epi8(0x80);
-#endif
-
-
-
-  //determine number of bits in codeword
-  if (BG==1)
-    {
-      nrows=46; //parity check bits
-      ncols=22; //info bits
-      rate=3;
-    }
-    else if (BG==2)
-    {
-      nrows=42; //parity check bits
-      ncols=10; // info bits
-      rate=5;
-    }
-
-#ifdef DEBUG_LDPC
-  LOG_D(PHY,"ldpc_encoder_optim_8seg: BG %d, Zc %d, Kb %d, block_length %d, segments %d\n",BG,Zc,Kb,block_length,n_segments);
-  LOG_D(PHY,"ldpc_encoder_optim_8seg: PDU (seg 0) %x %x %x %x\n",test_input[0][0],test_input[0][1],test_input[0][2],test_input[0][3]);
-#endif
-
-  AssertFatal(Zc>0,"no valid Zc found for block length %d\n",block_length);
-
-  if ((Zc&31) > 0) simd_size = 16;
-  else          simd_size = 32;
-
-  unsigned char c[22*Zc] __attribute__((aligned(32))); //padded input, unpacked, max size
-  unsigned char d[46*Zc] __attribute__((aligned(32))); //coded parity part output, unpacked, max size
-
-  unsigned char c_extension[2*22*Zc*simd_size] __attribute__((aligned(32)));      //double size matrix of c
-
-  // calculate number of punctured bits
-  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
-  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate);
-  //printf("%d\n",no_punctured_columns);
-  //printf("%d\n",removed_bit);
-  // unpack input
-  memset(c,0,sizeof(unsigned char) * ncols * Zc);
-  memset(d,0,sizeof(unsigned char) * nrows * Zc);
-
-  if(tinput != NULL) start_meas(tinput);
-#if 0
-  for (i=0; i<block_length; i++) {
-	//for (j=0; j<n_segments; j++) {
-    for (j=macro_segment; j < macro_segment_end; j++) {
-
-      temp = (test_input[j][i/8]&(1<<(i&7)))>>(i&7);
-      //printf("c(%d,%d)=%d\n",j,i,temp);
-      c[i] |= (temp << (j-macro_segment));
-    }
-  }
-#else
-#ifdef __AVX2__
-  for (i=0; i<block_length>>5; i++) {
-    c256 = _mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[macro_segment])[i]), shufmask),andmask),zero256),masks[0]);
-    //for (j=1; j<n_segments; j++) {
-    for (j=macro_segment+1; j < macro_segment_end; j++) {    
-      c256 = _mm256_or_si256(_mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[j])[i]), shufmask),andmask),zero256),masks[j-macro_segment]),c256);
-    }
-    ((__m256i *)c)[i] = c256;
-  }
-
-  for (i=(block_length>>5)<<5;i<block_length;i++) {
-    //for (j=0; j<n_segments; j++) {
-	  for (j=macro_segment; j < macro_segment_end; j++) {
-
-	    temp = (test_input[j][i/8]&(128>>(i&7)))>>(7-(i&7));
-      //printf("c(%d,%d)=%d\n",j,i,temp);
-      c[i] |= (temp << (j-macro_segment));
-    }
-  }
-#else
-  AssertFatal(1==0,"Need AVX2 for this\n");
-#endif
-#endif
-
-  if(tinput != NULL) stop_meas(tinput);
-
-  if ((BG==1 && Zc>176) || (BG==2 && Zc>64)) {
-    // extend matrix
-    if(tprep != NULL) start_meas(tprep);
-    for (i1=0; i1 < ncols; i1++)
-      {
-	memcpy(&c_extension[2*i1*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
-	memcpy(&c_extension[(2*i1+1)*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
-      }
-    for (i1=1;i1<simd_size;i1++) {
-      memcpy(&c_extension[(2*ncols*Zc*i1)], &c_extension[i1], (2*ncols*Zc*sizeof(unsigned char))-i1);
-      //    memset(&c_extension[(2*ncols*Zc*i1)],0,i1);
-      /*
-	printf("shift %d: ",i1);
-	for (int j=0;j<64;j++) printf("%d ",c_extension[(2*ncols*Zc*i1)+j]);
-	printf("\n");
-      */
-    }
-    if(tprep != NULL) stop_meas(tprep);
-    //parity check part
-    if(tparity != NULL) start_meas(tparity);
-    encode_parity_check_part_optim(c_extension, d, BG, Zc, Kb);
-    if(tparity != NULL) stop_meas(tparity);
-  }
-  else {
-    if (encode_parity_check_part_orig(c, d, BG, Zc, Kb, block_length)!=0) {
-      printf("Problem with encoder\n");
-      return(-1);
-    }
-  }
-  if(toutput != NULL) start_meas(toutput);
-  // information part and puncture columns
-  /*
-  memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
-  memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
-  */
-#ifdef __AVX2__
-  if ((((2*Zc)&31) == 0) && (((block_length-(2*Zc))&31) == 0)) {
-    //AssertFatal(((2*Zc)&31) == 0,"2*Zc needs to be a multiple of 32 for now\n");
-    //AssertFatal(((block_length-(2*Zc))&31) == 0,"block_length-(2*Zc) needs to be a multiple of 32 for now\n");
-    uint32_t l1 = (block_length-(2*Zc))>>5;
-    uint32_t l2 = ((nrows-no_punctured_columns) * Zc-removed_bit)>>5;
-    __m256i *c256p = (__m256i *)&c[2*Zc];
-    __m256i *d256p = (__m256i *)&d[0];
-    //  if (((block_length-(2*Zc))&31)>0) l1++;
-
-    for (i=0;i<l1;i++)
-      //for (j=0;j<n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(c256p[i],j),masks[0]);
-    	for (j=macro_segment; j < macro_segment_end; j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(c256p[i],j-macro_segment),masks[0]);
-
-
-    //  if ((((nrows-no_punctured_columns) * Zc-removed_bit)&31)>0) l2++;
-
-    for (i1=0;i1<l2;i1++,i++)
-      //for (j=0;j<n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(d256p[i1],j),masks[0]);
-    	for (j=macro_segment; j < macro_segment_end; j++)  ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(d256p[i1],j-macro_segment),masks[0]);
-  }
-  else {
-#ifdef DEBUG_LDPC
-  LOG_W(PHY,"using non-optimized version\n");
-#endif
-    // do non-SIMD version
-    for (i=0;i<(block_length-2*Zc);i++)
-      //for (j=0; j<n_segments; j++)
-      for (j=macro_segment; j < macro_segment_end; j++)
-	channel_input[j][i] = (c[2*Zc+i]>>(j-macro_segment))&1;
-    for (i=0;i<((nrows-no_punctured_columns) * Zc-removed_bit);i++)
-      //for (j=0; j<n_segments; j++)
-    	  for (j=macro_segment; j < macro_segment_end; j++)
-	channel_input[j][block_length-2*Zc+i] = (d[i]>>(j-macro_segment))&1;
-    }
-
-#else
-    AssertFatal(1==0,"Need AVX2 for now\n");
-#endif
-
-  if(toutput != NULL) stop_meas(toutput);
-  return 0;
-}
-
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c
new file mode 100644
index 0000000000000000000000000000000000000000..7da265494a020138a2c123ed1dcbe4c0e8d394ea
--- /dev/null
+++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+/*!\file ldpc_encoder2.c
+ * \brief Defines the optimized LDPC encoder
+ * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom)
+ * \email openair_tech@eurecom.fr
+ * \date 27-03-2018
+ * \version 1.0
+ * \note
+ * \warning
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <types.h>
+#include "assertions.h"
+#include "common/utils/LOG/log.h"
+#include "PHY/TOOLS/time_meas.h"
+#include "openair1/PHY/CODING/nrLDPC_defs.h"
+#include "ldpc_encode_parity_check.c"
+#include "ldpc_generate_coefficient.c"
+//#define DEBUG_LDPC
+
+
+
+
+
+int nrLDPC_encod(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, encoder_implemparams_t *impp)
+{
+
+  short nrows=0,ncols=0;
+  int i,i1,rate=3;
+  int no_punctured_columns,removed_bit;
+
+  int simd_size;
+
+  //determine number of bits in codeword
+   //if (block_length>3840)
+   if (BG==1)
+     {
+       //BG=1;
+       nrows=46; //parity check bits
+       ncols=22; //info bits
+       rate=3;
+     }
+     //else if (block_length<=3840)
+    else if	(BG==2)
+     {
+       //BG=2;
+       nrows=42; //parity check bits
+       ncols=10; // info bits
+       rate=5;
+
+       }
+
+
+#ifdef DEBUG_LDPC
+  LOG_D(PHY,"ldpc_encoder_optim_8seg: BG %d, Zc %d, Kb %d, block_length %d\n",BG,Zc,Kb,block_length);
+  LOG_D(PHY,"ldpc_encoder_optim_8seg: PDU %x %x %x %x\n",test_input[0][0],test_input[0][1],test_input[0][2],test_input[0][3]);
+#endif
+
+  if ((Zc&31) > 0) simd_size = 16;
+  else simd_size = 32;
+
+  unsigned char c[22*Zc] __attribute__((aligned(32))); //padded input, unpacked, max size
+  unsigned char d[46*Zc] __attribute__((aligned(32))); //coded parity part output, unpacked, max size
+
+  unsigned char c_extension[2*22*Zc*simd_size] __attribute__((aligned(32)));      //double size matrix of c
+
+  // calculate number of punctured bits
+  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
+  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate);
+  // printf("%d\n",no_punctured_columns);
+  // printf("%d\n",removed_bit);
+  // unpack input
+  memset(c,0,sizeof(unsigned char) * ncols * Zc);
+  memset(d,0,sizeof(unsigned char) * nrows * Zc);
+
+  if(impp->tinput != NULL) start_meas(impp->tinput);
+  for (i=0; i<block_length; i++) {
+    c[i] = (test_input[0][i/8]&(128>>(i&7)))>>(7-(i&7));
+      //printf("c(%d,%d)=%d\n",j,i,temp);
+    }
+
+  if(impp->tinput != NULL) stop_meas(impp->tinput);
+
+  if ((BG==1 && Zc>176) || (BG==2 && Zc>64)) { 
+    // extend matrix
+    if(impp->tprep != NULL) start_meas(impp->tprep);
+    for (i1=0; i1 < ncols; i1++)
+      {
+	memcpy(&c_extension[2*i1*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
+	memcpy(&c_extension[(2*i1+1)*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
+      }
+    for (i1=1;i1<simd_size;i1++) {
+      memcpy(&c_extension[(2*ncols*Zc*i1)], &c_extension[i1], (2*ncols*Zc*sizeof(unsigned char))-i1);
+      //    memset(&c_extension[(2*ncols*Zc*i1)],0,i1);
+      /*
+	printf("shift %d: ",i1);
+	for (int j=0;j<64;j++) printf("%d ",c_extension[(2*ncols*Zc*i1)+j]);
+	printf("\n");
+      */
+    }
+    if(impp->tprep != NULL) stop_meas(impp->tprep);
+    //parity check part
+    if(impp->tparity != NULL) start_meas(impp->tparity);
+    encode_parity_check_part_optim(c_extension, d, BG, Zc, Kb);
+    if(impp->tparity != NULL) stop_meas(impp->tparity);
+  }
+  else {
+    if (encode_parity_check_part_orig(c, d, BG, Zc, Kb, block_length)!=0) {
+      printf("Problem with encoder\n");
+      return(-1);
+    }
+  }
+  if(impp->toutput != NULL) start_meas(impp->toutput);
+  // information part and puncture columns
+  memcpy(&channel_input[0][0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
+  memcpy(&channel_input[0][block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
+
+  if(impp->toutput != NULL) stop_meas(impp->toutput);
+  return 0;
+}
+
+
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c
new file mode 100644
index 0000000000000000000000000000000000000000..a974e86e27c428c47574c0d7635f8cfd35ffbbff
--- /dev/null
+++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c
@@ -0,0 +1,225 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+/*!\file ldpc_encoder2.c
+ * \brief Defines the optimized LDPC encoder
+ * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom)
+ * \email openair_tech@eurecom.fr
+ * \date 27-03-2018
+ * \version 1.0
+ * \note
+ * \warning
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <types.h>
+#include "assertions.h"
+#include "common/utils/LOG/log.h"
+#include "PHY/TOOLS/time_meas.h"
+#include "openair1/PHY/CODING/nrLDPC_defs.h"
+//#define DEBUG_LDPC
+#include "ldpc_encode_parity_check.c" 
+#include "ldpc_generate_coefficient.c"
+
+
+
+int nrLDPC_encod(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, encoder_implemparams_t *impp)
+{
+
+  short nrows=0,ncols=0;
+  int i,i1,j,rate=3;
+  int no_punctured_columns,removed_bit;
+  char temp;
+  int simd_size;
+
+#ifdef __AVX2__
+  __m256i shufmask = _mm256_set_epi64x(0x0303030303030303, 0x0202020202020202,0x0101010101010101, 0x0000000000000000);
+  __m256i andmask  = _mm256_set1_epi64x(0x0102040810204080);  // every 8 bits -> 8 bytes, pattern repeats.
+  __m256i zero256   = _mm256_setzero_si256();
+  __m256i masks[8];
+  register __m256i c256;
+  masks[0] = _mm256_set1_epi8(0x1);
+  masks[1] = _mm256_set1_epi8(0x2);
+  masks[2] = _mm256_set1_epi8(0x4);
+  masks[3] = _mm256_set1_epi8(0x8);
+  masks[4] = _mm256_set1_epi8(0x10);
+  masks[5] = _mm256_set1_epi8(0x20);
+  masks[6] = _mm256_set1_epi8(0x40);
+  masks[7] = _mm256_set1_epi8(0x80);
+#endif
+
+  AssertFatal((impp->n_segments>0&&impp->n_segments<=8),"0 < n_segments %d <= 8\n",impp->n_segments);
+
+  //determine number of bits in codeword
+  //if (block_length>3840)
+  if (BG==1)
+    {
+      nrows=46; //parity check bits
+      ncols=22; //info bits
+      rate=3;
+    }
+    //else if (block_length<=3840)
+   else if	(BG==2)
+    {
+      //BG=2;
+      nrows=42; //parity check bits
+      ncols=10; // info bits
+      rate=5;
+
+      }
+
+#ifdef DEBUG_LDPC
+  LOG_D(PHY,"ldpc_encoder_optim_8seg: BG %d, Zc %d, Kb %d, block_length %d, segments %d\n",BG,Zc,Kb,block_length,n_segments);
+  LOG_D(PHY,"ldpc_encoder_optim_8seg: PDU (seg 0) %x %x %x %x\n",test_input[0][0],test_input[0][1],test_input[0][2],test_input[0][3]);
+#endif
+
+  AssertFatal(Zc>0,"no valid Zc found for block length %d\n",block_length);
+
+  if ((Zc&31) > 0) simd_size = 16;
+  else          simd_size = 32;
+
+  unsigned char c[22*Zc] __attribute__((aligned(32))); //padded input, unpacked, max size
+  unsigned char d[46*Zc] __attribute__((aligned(32))); //coded parity part output, unpacked, max size
+
+  unsigned char c_extension[2*22*Zc*simd_size] __attribute__((aligned(32)));      //double size matrix of c
+
+  // calculate number of punctured bits
+  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
+  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate);
+  // printf("%d\n",no_punctured_columns);
+  // printf("%d\n",removed_bit);
+  // unpack input
+  memset(c,0,sizeof(unsigned char) * ncols * Zc);
+  memset(d,0,sizeof(unsigned char) * nrows * Zc);
+
+  if(impp->tinput != NULL) start_meas(impp->tinput);
+#if 0
+  for (i=0; i<block_length; i++) {
+    for (j=0; j<n_segments; j++) {
+
+      temp = (test_input[j][i/8]&(128>>(i&7)))>>(7-(i&7));
+      //printf("c(%d,%d)=%d\n",j,i,temp);
+      c[i] |= (temp << j);
+    }
+  }
+#else
+#ifdef __AVX2__
+  for (i=0; i<block_length>>5; i++) {
+    c256 = _mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[0])[i]), shufmask),andmask),zero256),masks[0]);
+    for (j=1; j<impp->n_segments; j++) {
+      c256 = _mm256_or_si256(_mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[j])[i]), shufmask),andmask),zero256),masks[j]),c256);
+    }
+    ((__m256i *)c)[i] = c256;
+  }
+
+  for (i=(block_length>>5)<<5;i<block_length;i++) {
+    for (j=0; j<impp->n_segments; j++) {
+
+      temp = (test_input[j][i/8]&(128>>(i&7)))>>(7-(i&7));
+      //printf("c(%d,%d)=%d\n",j,i,temp);
+      c[i] |= (temp << j);
+    }
+  }
+#else
+  AssertFatal(1==0,"Need AVX2 for this\n");
+#endif
+#endif
+
+  if(impp->tinput != NULL) stop_meas(impp->tinput);
+
+  if ((BG==1 && Zc>176) || (BG==2 && Zc>64)) { 
+    // extend matrix
+    if(impp->tprep != NULL) start_meas(impp->tprep);
+    for (i1=0; i1 < ncols; i1++)
+      {
+	memcpy(&c_extension[2*i1*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
+	memcpy(&c_extension[(2*i1+1)*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
+      }
+    for (i1=1;i1<simd_size;i1++) {
+      memcpy(&c_extension[(2*ncols*Zc*i1)], &c_extension[i1], (2*ncols*Zc*sizeof(unsigned char))-i1);
+      //    memset(&c_extension[(2*ncols*Zc*i1)],0,i1);
+      /*
+	printf("shift %d: ",i1);
+	for (int j=0;j<64;j++) printf("%d ",c_extension[(2*ncols*Zc*i1)+j]);
+	printf("\n");
+      */
+    }
+    if(impp->tprep != NULL) stop_meas(impp->tprep);
+    //parity check part
+    if(impp->tparity != NULL) start_meas(impp->tparity);
+    encode_parity_check_part_optim(c_extension, d, BG, Zc, Kb);
+    if(impp->tparity != NULL) stop_meas(impp->tparity);
+  }
+  else {
+    if (encode_parity_check_part_orig(c, d, BG, Zc, Kb, block_length)!=0) {
+      printf("Problem with encoder\n");
+      return(-1);
+    }
+  }
+  if(impp->toutput != NULL) start_meas(impp->toutput);
+  // information part and puncture columns
+  /*
+  memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
+  memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
+  */
+#ifdef __AVX2__
+  if ((((2*Zc)&31) == 0) && (((block_length-(2*Zc))&31) == 0)) {
+    //AssertFatal(((2*Zc)&31) == 0,"2*Zc needs to be a multiple of 32 for now\n");
+    //AssertFatal(((block_length-(2*Zc))&31) == 0,"block_length-(2*Zc) needs to be a multiple of 32 for now\n");
+    uint32_t l1 = (block_length-(2*Zc))>>5;
+    uint32_t l2 = ((nrows-no_punctured_columns) * Zc-removed_bit)>>5;
+    __m256i *c256p = (__m256i *)&c[2*Zc];
+    __m256i *d256p = (__m256i *)&d[0];
+    //  if (((block_length-(2*Zc))&31)>0) l1++;
+    
+    for (i=0;i<l1;i++)
+      for (j=0;j<impp->n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(c256p[i],j),masks[0]);
+    
+    //  if ((((nrows-no_punctured_columns) * Zc-removed_bit)&31)>0) l2++;
+    
+    for (i1=0;i1<l2;i1++,i++)
+      for (j=0;j<impp->n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(d256p[i1],j),masks[0]);
+  }
+  else {
+#ifdef DEBUG_LDPC
+  LOG_W(PHY,"using non-optimized version\n");
+#endif
+    // do non-SIMD version
+    for (i=0;i<(block_length-2*Zc);i++) 
+      for (j=0; j<impp->n_segments; j++)
+	channel_input[j][i] = (c[2*Zc+i]>>j)&1;
+    for (i=0;i<((nrows-no_punctured_columns) * Zc-removed_bit);i++)
+      for (j=0; j<impp->n_segments; j++)
+	channel_input[j][block_length-2*Zc+i] = (d[i]>>j)&1;
+    }
+
+#else
+    AssertFatal(1==0,"Need AVX2 for now\n");
+#endif
+
+  if(impp->toutput != NULL) stop_meas(impp->toutput);
+  return 0;
+}
+
+
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
new file mode 100644
index 0000000000000000000000000000000000000000..28ab5b50293314cd05d41c2201502af56e5effc8
--- /dev/null
+++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
@@ -0,0 +1,238 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+/*!\file ldpc_encoder2.c
+ * \brief Defines the optimized LDPC encoder
+ * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom)
+ * \email openair_tech@eurecom.fr
+ * \date 27-03-2018
+ * \version 1.0
+ * \note
+ * \warning
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <types.h>
+#include "assertions.h"
+#include "common/utils/LOG/log.h"
+#include "PHY/TOOLS/time_meas.h"
+#include "openair1/PHY/CODING/nrLDPC_defs.h"
+
+//#define DEBUG_LDPC
+
+#include "ldpc_encode_parity_check.c"
+#include "ldpc_generate_coefficient.c"
+
+
+int nrLDPC_encod(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, encoder_implemparams_t *impp)
+{
+
+  short nrows=0,ncols=0;
+  int i,i1,j,rate=3;
+  int no_punctured_columns,removed_bit;
+  //Table of possible lifting sizes
+  char temp;
+  int simd_size;
+  unsigned int macro_segment, macro_segment_end;
+
+  
+  macro_segment = 8*impp->macro_num;
+  // macro_segment_end = (n_segments > 8*(macro_num+1)) ? 8*(macro_num+1) : n_segments;
+  macro_segment_end = macro_segment + (impp->n_segments > 8 ? 8 : impp->n_segments);
+  ///printf("macro_segment: %d\n", macro_segment);
+  ///printf("macro_segment_end: %d\n", macro_segment_end );
+
+#ifdef __AVX2__
+  __m256i shufmask = _mm256_set_epi64x(0x0303030303030303, 0x0202020202020202,0x0101010101010101, 0x0000000000000000);
+  __m256i andmask  = _mm256_set1_epi64x(0x0102040810204080);  // every 8 bits -> 8 bytes, pattern repeats.
+  __m256i zero256   = _mm256_setzero_si256();
+  __m256i masks[8];
+  register __m256i c256;
+  masks[0] = _mm256_set1_epi8(0x1);
+  masks[1] = _mm256_set1_epi8(0x2);
+  masks[2] = _mm256_set1_epi8(0x4);
+  masks[3] = _mm256_set1_epi8(0x8);
+  masks[4] = _mm256_set1_epi8(0x10);
+  masks[5] = _mm256_set1_epi8(0x20);
+  masks[6] = _mm256_set1_epi8(0x40);
+  masks[7] = _mm256_set1_epi8(0x80);
+#endif
+
+
+
+  //determine number of bits in codeword
+  if (BG==1)
+    {
+      nrows=46; //parity check bits
+      ncols=22; //info bits
+      rate=3;
+    }
+    else if (BG==2)
+    {
+      nrows=42; //parity check bits
+      ncols=10; // info bits
+      rate=5;
+    }
+
+#ifdef DEBUG_LDPC
+  LOG_D(PHY,"ldpc_encoder_optim_8seg: BG %d, Zc %d, Kb %d, block_length %d, segments %d\n",BG,Zc,Kb,block_length,n_segments);
+  LOG_D(PHY,"ldpc_encoder_optim_8seg: PDU (seg 0) %x %x %x %x\n",test_input[0][0],test_input[0][1],test_input[0][2],test_input[0][3]);
+#endif
+
+  AssertFatal(Zc>0,"no valid Zc found for block length %d\n",block_length);
+
+  if ((Zc&31) > 0) simd_size = 16;
+  else          simd_size = 32;
+
+  unsigned char c[22*Zc] __attribute__((aligned(32))); //padded input, unpacked, max size
+  unsigned char d[46*Zc] __attribute__((aligned(32))); //coded parity part output, unpacked, max size
+
+  unsigned char c_extension[2*22*Zc*simd_size] __attribute__((aligned(32)));      //double size matrix of c
+
+  // calculate number of punctured bits
+  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
+  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate);
+  //printf("%d\n",no_punctured_columns);
+  //printf("%d\n",removed_bit);
+  // unpack input
+  memset(c,0,sizeof(unsigned char) * ncols * Zc);
+  memset(d,0,sizeof(unsigned char) * nrows * Zc);
+
+  if(impp->tinput != NULL) start_meas(impp->tinput);
+#if 0
+  for (i=0; i<block_length; i++) {
+	//for (j=0; j<n_segments; j++) {
+    for (j=macro_segment; j < macro_segment_end; j++) {
+
+      temp = (test_input[j][i/8]&(1<<(i&7)))>>(i&7);
+      //printf("c(%d,%d)=%d\n",j,i,temp);
+      c[i] |= (temp << (j-macro_segment));
+    }
+  }
+#else
+#ifdef __AVX2__
+  for (i=0; i<block_length>>5; i++) {
+    c256 = _mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[macro_segment])[i]), shufmask),andmask),zero256),masks[0]);
+    //for (j=1; j<n_segments; j++) {
+    for (j=macro_segment+1; j < macro_segment_end; j++) {    
+      c256 = _mm256_or_si256(_mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[j])[i]), shufmask),andmask),zero256),masks[j-macro_segment]),c256);
+    }
+    ((__m256i *)c)[i] = c256;
+  }
+
+  for (i=(block_length>>5)<<5;i<block_length;i++) {
+    //for (j=0; j<n_segments; j++) {
+	  for (j=macro_segment; j < macro_segment_end; j++) {
+
+	    temp = (test_input[j][i/8]&(128>>(i&7)))>>(7-(i&7));
+      //printf("c(%d,%d)=%d\n",j,i,temp);
+      c[i] |= (temp << (j-macro_segment));
+    }
+  }
+#else
+  AssertFatal(1==0,"Need AVX2 for this\n");
+#endif
+#endif
+
+  if(impp->tinput != NULL) stop_meas(impp->tinput);
+
+  if ((BG==1 && Zc>176) || (BG==2 && Zc>64)) {
+    // extend matrix
+    if(impp->tprep != NULL) start_meas(impp->tprep);
+    for (i1=0; i1 < ncols; i1++)
+      {
+	memcpy(&c_extension[2*i1*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
+	memcpy(&c_extension[(2*i1+1)*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
+      }
+    for (i1=1;i1<simd_size;i1++) {
+      memcpy(&c_extension[(2*ncols*Zc*i1)], &c_extension[i1], (2*ncols*Zc*sizeof(unsigned char))-i1);
+      //    memset(&c_extension[(2*ncols*Zc*i1)],0,i1);
+      /*
+	printf("shift %d: ",i1);
+	for (int j=0;j<64;j++) printf("%d ",c_extension[(2*ncols*Zc*i1)+j]);
+	printf("\n");
+      */
+    }
+    if(impp->tprep != NULL) stop_meas(impp->tprep);
+    //parity check part
+    if(impp->tparity != NULL) start_meas(impp->tparity);
+    encode_parity_check_part_optim(c_extension, d, BG, Zc, Kb);
+    if(impp->tparity != NULL) stop_meas(impp->tparity);
+  }
+  else {
+    if (encode_parity_check_part_orig(c, d, BG, Zc, Kb, block_length)!=0) {
+      printf("Problem with encoder\n");
+      return(-1);
+    }
+  }
+  if(impp->toutput != NULL) start_meas(impp->toutput);
+  // information part and puncture columns
+  /*
+  memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
+  memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
+  */
+#ifdef __AVX2__
+  if ((((2*Zc)&31) == 0) && (((block_length-(2*Zc))&31) == 0)) {
+    //AssertFatal(((2*Zc)&31) == 0,"2*Zc needs to be a multiple of 32 for now\n");
+    //AssertFatal(((block_length-(2*Zc))&31) == 0,"block_length-(2*Zc) needs to be a multiple of 32 for now\n");
+    uint32_t l1 = (block_length-(2*Zc))>>5;
+    uint32_t l2 = ((nrows-no_punctured_columns) * Zc-removed_bit)>>5;
+    __m256i *c256p = (__m256i *)&c[2*Zc];
+    __m256i *d256p = (__m256i *)&d[0];
+    //  if (((block_length-(2*Zc))&31)>0) l1++;
+
+    for (i=0;i<l1;i++)
+      //for (j=0;j<n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(c256p[i],j),masks[0]);
+    	for (j=macro_segment; j < macro_segment_end; j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(c256p[i],j-macro_segment),masks[0]);
+
+
+    //  if ((((nrows-no_punctured_columns) * Zc-removed_bit)&31)>0) l2++;
+
+    for (i1=0;i1<l2;i1++,i++)
+      //for (j=0;j<n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(d256p[i1],j),masks[0]);
+    	for (j=macro_segment; j < macro_segment_end; j++)  ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(d256p[i1],j-macro_segment),masks[0]);
+  }
+  else {
+#ifdef DEBUG_LDPC
+  LOG_W(PHY,"using non-optimized version\n");
+#endif
+    // do non-SIMD version
+    for (i=0;i<(block_length-2*Zc);i++)
+      //for (j=0; j<n_segments; j++)
+      for (j=macro_segment; j < macro_segment_end; j++)
+	channel_input[j][i] = (c[2*Zc+i]>>(j-macro_segment))&1;
+    for (i=0;i<((nrows-no_punctured_columns) * Zc-removed_bit);i++)
+      //for (j=0; j<n_segments; j++)
+    	  for (j=macro_segment; j < macro_segment_end; j++)
+	channel_input[j][block_length-2*Zc+i] = (d[i]>>(j-macro_segment))&1;
+    }
+
+#else
+    AssertFatal(1==0,"Need AVX2 for now\n");
+#endif
+
+  if(impp->toutput != NULL) stop_meas(impp->toutput);
+  return 0;
+}
+
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c
index 5988c9067d0d32a67fbd694f6a9e0398b3f747ec..3d26a190639f4ddac14cc70895f6b00fbb3558dd 100644
--- a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c
+++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c
@@ -35,9 +35,8 @@
 #include <string.h>
 #include "Gen_shift_value.h"
 #include "assertions.h"
-#include "defs.h"
 
-short *choose_generator_matrix(short BG,short Zc)
+static inline short *choose_generator_matrix(short BG,short Zc)
 {
   short *Gen_shift_values = NULL;
 
@@ -361,237 +360,70 @@ short *choose_generator_matrix(short BG,short Zc)
   return Gen_shift_values;
 }
 
-int ldpc_encoder_orig(unsigned char *test_input,unsigned char *channel_input,int Zc,int Kb,short block_length, short BG,unsigned char gen_code)
+static inline int encode_parity_check_part_orig(unsigned char *c,unsigned char *d, short BG,short Zc,short Kb,short block_length)
 {
-  unsigned char c[22*384]; //padded input, unpacked, max size
-  unsigned char d[68*384]; //coded output, unpacked, max size
+  short *Gen_shift_values=choose_generator_matrix(BG,Zc);
+  short *no_shift_values, *pointer_shift_values;
+  int no_punctured_columns;
+  short nrows,ncols,rate=3;
+  int i1,i2,i3,i4,i5,temp_prime;
   unsigned char channel_temp,temp;
-  short *Gen_shift_values, *no_shift_values, *pointer_shift_values;
-
-  short nrows = 46;//parity check bits
-  short ncols = 22;//info bits
-
-
-  int i,i1,i2,i3,i4,i5,temp_prime,var;
-  int no_punctured_columns,removed_bit,rate=3;
-  int nind=0;
-  int indlist[1000];
-  int indlist2[1000];
-
-  //determine number of bits in codeword
-  //if (block_length>3840)
-     if (BG==1)
-       {
-         nrows=46; //parity check bits
-         ncols=22; //info bits
-         rate=3;
-       }
-       //else if (block_length<=3840)
-      else if	(BG==2)
-       {
-         //BG=2;
-         nrows=42; //parity check bits
-         ncols=10; // info bits
-         rate=5;
-         }
-
-  Gen_shift_values=choose_generator_matrix(BG,Zc);
-  if (Gen_shift_values==NULL) {
-    printf("ldpc_encoder_orig: could not find generator matrix\n");
-    return(-1);
-  }
-
-  //printf("ldpc_encoder_orig: BG %d, Zc %d, Kb %d\n",BG, Zc, Kb);
 
-  // load base graph of generator matrix
   if (BG==1)
   {
     no_shift_values=(short *) no_shift_values_BG1;
     pointer_shift_values=(short *) pointer_shift_values_BG1;
+      nrows=46; //parity check bits
+      ncols=22; //info bits
+      rate=3;
   }
   else if (BG==2)
   {
     no_shift_values=(short *) no_shift_values_BG2;
     pointer_shift_values=(short *) pointer_shift_values_BG2;
+      nrows=42; //parity check bits
+      ncols=10; //info bits
+      rate=5;
   }
   else {
-    AssertFatal(0,"BG %d is not supported yet\n",BG);
-  }
-  
-  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
-  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(block_length*rate);
-  //printf("%d\n",no_punctured_columns);
-  //printf("%d\n",removed_bit);
-  // unpack input
-  memset(c,0,sizeof(unsigned char) * ncols * Zc);
-  memset(d,0,sizeof(unsigned char) * nrows * Zc);
-
-  for (i=0; i<block_length; i++)
-  {
-    //c[i] = test_input[i/8]<<(i%8);
-    //c[i]=c[i]>>7&1;
-    c[i]=(test_input[i/8]&(128>>(i&7)))>>(7-(i&7));
+    printf("problem with BG\n");
+    return(-1);
   }
 
-  // parity check part
-
-  if (gen_code==1)
-  {
-    char fname[100];
-    sprintf(fname,"ldpc_BG%d_Zc%d_byte.c",BG,Zc);
-    FILE *fd=fopen(fname,"w");
-    AssertFatal(fd!=NULL,"cannot open %s\n",fname);
-    sprintf(fname,"ldpc_BG%d_Zc%d_16bit.c",BG,Zc);
-    FILE *fd2=fopen(fname,"w");
-    AssertFatal(fd2!=NULL,"cannot open %s\n",fname);
-
-    int shift;
-    char data_type[100];
-    char xor_command[100];
-    int mask;
-
-
 
+  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
 
-    fprintf(fd,"#include \"PHY/sse_intrin.h\"\n");
-    fprintf(fd2,"#include \"PHY/sse_intrin.h\"\n");
+  //printf("no_punctured_columns = %d\n",no_punctured_columns);
 
-    if ((Zc&31)==0) {
-      shift=5; // AVX2 - 256-bit SIMD
-      mask=31;
-      strcpy(data_type,"__m256i");
-      strcpy(xor_command,"_mm256_xor_si256");
-    }
-    else if ((Zc&15)==0) {
-      shift=4; // SSE4 - 128-bit SIMD
-      mask=15;
-      strcpy(data_type,"__m128i");
-      strcpy(xor_command,"_mm_xor_si128");
+  for (i2=0; i2 < Zc; i2++)
+  {
+    //t=Kb*Zc+i2;
 
-    }
-    else if ((Zc&7)==0) {
-      shift=3; // MMX  - 64-bit SIMD
-      mask=7;
-      strcpy(data_type,"__m64");
-      strcpy(xor_command,"_mm_xor_si64"); 
-    }
-    else {
-      shift=0;                 // no SIMD
-      mask=0;
-      strcpy(data_type,"uint8_t");
-      strcpy(xor_command,"scalar_xor");
-      fprintf(fd,"#define scalar_xor(a,b) ((a)^(b))\n");
-      fprintf(fd2,"#define scalar_xor(a,b) ((a)^(b))\n");
-    }
-    fprintf(fd,"// generated code for Zc=%d, byte encoding\n",Zc);
-    fprintf(fd2,"// generated code for Zc=%d, 16bit encoding\n",Zc);
-    fprintf(fd,"static inline void ldpc_BG%d_Zc%d_byte(uint8_t *c,uint8_t *d) {\n",BG,Zc);
-    fprintf(fd2,"static inline void ldpc_BG%d_Zc%d_16bit(uint16_t *c,uint16_t *d) {\n",BG,Zc);
-    fprintf(fd,"  %s *csimd=(%s *)c,*dsimd=(%s *)d;\n\n",data_type,data_type,data_type);
-    fprintf(fd2,"  %s *csimd=(%s *)c,*dsimd=(%s *)d;\n\n",data_type,data_type,data_type);
-    fprintf(fd,"  %s *c2,*d2;\n\n",data_type);
-    fprintf(fd2,"  %s *c2,*d2;\n\n",data_type);
-    fprintf(fd,"  int i2;\n");
-    fprintf(fd2,"  int i2;\n");
-    fprintf(fd,"  for (i2=0; i2<%d; i2++) {\n",Zc>>shift);
-    if (shift > 0)
-      fprintf(fd2,"  for (i2=0; i2<%d; i2++) {\n",Zc>>(shift-1));
-    for (i2=0; i2 < 1; i2++)
+    //rotate matrix here
+    for (i5=0; i5 < Kb; i5++)
     {
-      //t=Kb*Zc+i2;
-    
-      // calculate each row in base graph
-     
-
-      fprintf(fd,"     c2=&csimd[i2];\n");
-      fprintf(fd,"     d2=&dsimd[i2];\n");
-      fprintf(fd2,"     c2=&csimd[i2];\n");
-      fprintf(fd2,"     d2=&dsimd[i2];\n");
-
-      for (i1=0; i1 < nrows; i1++)
-
-      {
-        channel_temp=0;
-        fprintf(fd,"\n//row: %d\n",i1);
-        fprintf(fd2,"\n//row: %d\n",i1);
-	fprintf(fd,"     d2[%d]=",(Zc*i1)>>shift);
-	fprintf(fd2,"     d2[%d]=",(Zc*i1)>>(shift-1));
-
-        nind=0;
-
-        for (i3=0; i3 < ncols; i3++)
-        {
-          temp_prime=i1 * ncols + i3;
-
-
-	  for (i4=0; i4 < no_shift_values[temp_prime]; i4++)
-	    {
-	          
-	      var=(int)((i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc)/Zc);
-	      int index =var*2*Zc + (i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc) % Zc;
-	      
-	      indlist[nind] = ((index&mask)*((2*Zc)>>shift)*Kb)+(index>>shift);
-	      indlist2[nind++] = ((index&(mask>>1))*((2*Zc)>>(shift-1))*Kb)+(index>>(shift-1));
-	      
-	    }
-	  
-
-        }
-	for (i4=0;i4<nind-1;i4++) {
-	  fprintf(fd,"%s(c2[%d],",xor_command,indlist[i4]);
-	  fprintf(fd2,"%s(c2[%d],",xor_command,indlist2[i4]);
-	}
-	fprintf(fd,"c2[%d]",indlist[i4]);
-	fprintf(fd2,"c2[%d]",indlist2[i4]);
-	for (i4=0;i4<nind-1;i4++) { fprintf(fd,")"); fprintf(fd2,")"); }
-	fprintf(fd,";\n");
-	fprintf(fd2,";\n");
-
-      }
-      fprintf(fd,"  }\n}\n");
-      fprintf(fd2,"  }\n}\n");
+      temp = c[i5*Zc];
+      memmove(&c[i5*Zc], &c[i5*Zc+1], (Zc-1)*sizeof(unsigned char));
+      c[i5*Zc+Zc-1] = temp;
     }
-    fclose(fd);
-    fclose(fd2);
-  }
-  else if(gen_code==0)
-  {
-    for (i2=0; i2 < Zc; i2++)
-    {
-      //t=Kb*Zc+i2;
-
-      //rotate matrix here
-      for (i5=0; i5 < Kb; i5++)
-      {
-        temp = c[i5*Zc];
-        memmove(&c[i5*Zc], &c[i5*Zc+1], (Zc-1)*sizeof(unsigned char));
-        c[i5*Zc+Zc-1] = temp;
-      }
 
-      // calculate each row in base graph
-      for (i1=0; i1 < nrows-no_punctured_columns; i1++)
+    // calculate each row in base graph
+    for (i1=0; i1 < nrows-no_punctured_columns; i1++)
+    {
+      channel_temp=0;
+      for (i3=0; i3 < Kb; i3++)
       {
-        channel_temp=0;
+        temp_prime=i1 * ncols + i3;
 
-        for (i3=0; i3 < Kb; i3++)
+        for (i4=0; i4 < no_shift_values[temp_prime]; i4++)
         {
-          temp_prime=i1 * ncols + i3;
-
-          for (i4=0; i4 < no_shift_values[temp_prime]; i4++)
-          {
-            channel_temp = channel_temp ^ c[ i3*Zc + Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ] ];
-          }
+          channel_temp = channel_temp ^ c[ i3*Zc + Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ] ];
         }
-
-        d[i2+i1*Zc]=channel_temp;
-        //channel_input[t+i1*Zc]=channel_temp;
       }
+      d[i2+i1*Zc]=channel_temp;
+      //channel_input[t+i1*Zc]=channel_temp;
     }
   }
-
-  // information part and puncture columns
-  memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
-  memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
-  //memcpy(channel_input,c,Kb*Zc*sizeof(unsigned char));
-  return 0;
+  return(0);
 }
+
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h b/openair1/PHY/CODING/nrLDPC_extern.h
similarity index 60%
rename from openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h
rename to openair1/PHY/CODING/nrLDPC_extern.h
index 4d2401db831258b2e1bd8c9abf81e4239f550ae8..c0bfa0fdd8fea89ce82d01c388a5529057d1768a 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h
+++ b/openair1/PHY/CODING/nrLDPC_extern.h
@@ -18,29 +18,18 @@
  * For more information about the OpenAirInterface (OAI) Software Alliance:
  *      contact@openairinterface.org
  */
+#include "openair1/PHY/CODING/nrLDPC_defs.h"
 
-/*!\file nrLDPC_decoder.h
- * \brief Defines the LDPC decoder core prototypes
- * \author Sebastian Wagner (TCL Communications) Email: <mailto:sebastian.wagner@tcl.com>
- * \date 27-03-2018
- * \version 1.0
- * \note
- * \warning
- */
-
-#ifndef __NR_LDPC_DECODER__H__
-#define __NR_LDPC_DECODER__H__
-
-#include "nrLDPC_types.h"
-#include "nrLDPC_init_mem.h"
-
-/**
-   \brief LDPC decoder
-   \param p_decParams LDPC decoder parameters
-   \param p_llr Input LLRs
-   \param p_llrOut Output vector
-   \param p_profiler LDPC profiler statistics
-*/
-int32_t nrLDPC_decoder(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_llrOut, t_nrLDPC_procBuf* p_procBuf, t_nrLDPC_time_stats* p_profiler);
-
-#endif
+#ifdef LDPC_LOADER
+nrLDPC_decoderfunc_t nrLDPC_decoder;
+nrLDPC_encoderfunc_t nrLDPC_encoder;
+#else
+/* functions to load the LDPC shared lib, implemented in openair1/PHY/CODING/nrLDPC_load.c */
+extern int load_nrLDPClib(void) ;
+extern int load_nrLDPClib_ref(char *libversion, nrLDPC_encoderfunc_t * nrLDPC_encoder_ptr); // for ldpctest
+/* ldpc coder/decoder functions, as loaded by load_nrLDPClib(). */
+extern nrLDPC_decoderfunc_t nrLDPC_decoder;
+extern nrLDPC_encoderfunc_t nrLDPC_encoder;
+// inline functions:
+#include "openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init_mem.h"
+#endif
\ No newline at end of file
diff --git a/openair1/PHY/CODING/nrLDPC_load.c b/openair1/PHY/CODING/nrLDPC_load.c
new file mode 100644
index 0000000000000000000000000000000000000000..a74bdf7bd12a73c81ac6654f3e34495194e631a0
--- /dev/null
+++ b/openair1/PHY/CODING/nrLDPC_load.c
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+/*! \file openair1/PHY/CODING/coding_nr_load.c
+ * \brief: load library implementing coding/decoding algorithms
+ * \author Francois TABURET
+ * \date 2020
+ * \version 0.1
+ * \company NOKIA BellLabs France
+ * \email: francois.taburet@nokia-bell-labs.com
+ * \note
+ * \warning
+ */
+#define _GNU_SOURCE 
+#include <sys/types.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include "assertions.h"
+#include "common/utils/LOG/log.h"
+#define LDPC_LOADER
+#include "PHY/CODING/nrLDPC_extern.h"
+#include "common/config/config_userapi.h" 
+#include "common/utils/load_module_shlib.h" 
+
+
+/* function description array, to be used when loading the encoding/decoding shared lib */
+static loader_shlibfunc_t shlib_fdesc[2];
+
+char *arg[64]={"ldpctest","-O","cmdlineonly::dbgl0"};
+
+int load_nrLDPClib(void) {
+	 char *ptr = (char*)config_get_if();
+     if ( ptr==NULL )  {// phy simulators, config module possibly not loaded
+     	 load_configmodule(3,(char **)arg,CONFIG_ENABLECMDLINEONLY) ;
+     	 logInit();
+     }	 
+     shlib_fdesc[0].fname = "nrLDPC_decod";
+     shlib_fdesc[1].fname = "nrLDPC_encod";
+     int ret=load_module_shlib("ldpc",shlib_fdesc,sizeof(shlib_fdesc)/sizeof(loader_shlibfunc_t),NULL);
+     AssertFatal( (ret >= 0),"Error loading ldpc decoder");
+     nrLDPC_decoder = (nrLDPC_decoderfunc_t)shlib_fdesc[0].fptr;
+     nrLDPC_encoder = (nrLDPC_encoderfunc_t)shlib_fdesc[1].fptr;
+return 0;
+}
+
+int load_nrLDPClib_ref(char *libversion, nrLDPC_encoderfunc_t * nrLDPC_encoder_ptr) {
+	loader_shlibfunc_t shlib_encoder_fdesc;
+
+     shlib_encoder_fdesc.fname = "nrLDPC_encod";
+     char libpath[64];
+     sprintf(libpath,"ldpc%s",libversion);
+     int ret=load_module_shlib(libpath,&shlib_encoder_fdesc,1,NULL);
+     AssertFatal( (ret >= 0),"Error loading ldpc encoder %s\n",libpath);
+     *nrLDPC_encoder_ptr = (nrLDPC_encoderfunc_t)shlib_encoder_fdesc.fptr;
+return 0;
+}
+
+
diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c
index bf8f857a04e4bb433e4573023f6ebd4d73e8a4a5..9024823c04882853f3af00a5681bc73f7e096844 100644
--- a/openair1/PHY/INIT/nr_init.c
+++ b/openair1/PHY/INIT/nr_init.c
@@ -31,6 +31,7 @@
 #include "TDD-Config.h"
 #include "MBSFN-SubframeConfigList.h"*/
 #include "openair1/PHY/defs_RU.h"
+#include "openair1/PHY/CODING/nrLDPC_extern.h"
 #include "LAYER2/NR_MAC_gNB/mac_proto.h"
 #include "assertions.h"
 #include <math.h>
@@ -117,6 +118,7 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB,
   LOG_D(PHY,"[MSC_NEW][FRAME 00000][PHY_gNB][MOD %02"PRIu8"][]\n", gNB->Mod_id);
   crcTableInit();
   init_dfts();
+  load_nrLDPClib();
   // PBCH DMRS gold sequences generation
   nr_init_pbch_dmrs(gNB);
   //PDCCH DMRS init
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c
index dae5586224948a1b94dfe1d094b7d938a5854c3c..17de9c02af8c8cf338272f472e04f7c17afed013 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c
@@ -35,12 +35,11 @@
 #include "PHY/CODING/coding_extern.h"
 #include "PHY/CODING/coding_defs.h"
 #include "PHY/CODING/lte_interleaver_inline.h"
-#include "PHY/CODING/nrLDPC_encoder/defs.h"
+#include "PHY/CODING/nrLDPC_extern.h"
 #include "PHY/NR_TRANSPORT/nr_transport.h"
 #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
 #include "PHY/NR_TRANSPORT/nr_dlsch.h"
 #include "SCHED_NR/sched_nr.h"
-#include "defs.h"
 #include "common/utils/LOG/vcd_signal_dumper.h"
 #include "common/utils/LOG/log.h"
 #include <syscall.h>
@@ -404,9 +403,11 @@ int nr_dlsch_encoding(unsigned char *a,
       //ldpc_encoder_orig((unsigned char*)dlsch->harq_processes[harq_pid]->c[r],dlsch->harq_processes[harq_pid]->d[r],*Zc,Kb,Kr,BG,0);
       //ldpc_encoder_optim((unsigned char*)dlsch->harq_processes[harq_pid]->c[r],(unsigned char*)&dlsch->harq_processes[harq_pid]->d[r][0],*Zc,Kb,Kr,BG,NULL,NULL,NULL,NULL);
     }
-
+    encoder_implemparams_t impp;
+    impp.n_segments=dlsch->harq_processes[harq_pid]->C;
     for(int j=0;j<(dlsch->harq_processes[harq_pid]->C/8+1);j++) {
-      ldpc_encoder_optim_8seg_multi(dlsch->harq_processes[harq_pid]->c,dlsch->harq_processes[harq_pid]->d,*Zc,Kb,Kr,BG,dlsch->harq_processes[harq_pid]->C,j,NULL,NULL,NULL,NULL);
+      impp.macro_num=j;
+      nrLDPC_encoder(dlsch->harq_processes[harq_pid]->c,dlsch->harq_processes[harq_pid]->d,*Zc,Kb,Kr,BG,&impp);
     }
 
 
diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
index 3945439a45b495b487d48909bbb947d559e5b820..c58941b07712320756080d57220ec9b465638793 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
@@ -37,8 +37,7 @@
 #include "PHY/CODING/coding_extern.h"
 #include "PHY/CODING/coding_defs.h"
 #include "PHY/CODING/lte_interleaver_inline.h"
-#include "PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h"
-#include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h"
+#include "PHY/CODING/nrLDPC_extern.h"
 #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
 #include "PHY/NR_TRANSPORT/nr_ulsch.h"
 #include "PHY/NR_TRANSPORT/nr_dlsch.h"
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
index b3a95e313e1be4432db7d1c3fcc985a67768807f..b81c01114d2a39b2193597d9583c079ddfc70660 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
@@ -41,8 +41,7 @@
 #include "SCHED_NR_UE/defs.h"
 #include "SIMULATION/TOOLS/sim.h"
 #include "executables/nr-uesoftmodem.h"
-#include "PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h"
-#include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h"
+#include "PHY/CODING/nrLDPC_extern.h"
 //#define DEBUG_DLSCH_DECODING
 //#define ENABLE_PHY_PAYLOAD_DEBUG 1
 
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
index 2eb6dcd7fe682e84e6dd670cccb959aea84cf588..8b80b1b219f8af8ac12d2d45977228a3af065cbf 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
@@ -36,7 +36,7 @@
 #include "PHY/CODING/coding_defs.h"
 #include "PHY/CODING/coding_extern.h"
 #include "PHY/CODING/lte_interleaver_inline.h"
-#include "PHY/CODING/nrLDPC_encoder/defs.h"
+#include "PHY/CODING/nrLDPC_extern.h"
 #include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h"
 #include "common/utils/LOG/vcd_signal_dumper.h"
 
@@ -353,8 +353,11 @@ opp_enabled=0;
       printf("%d \n",  harq_process->d[0][cnt]);
       }
       printf("\n");*/
+    encoder_implemparams_t impp;
+    impp.n_segments=harq_process->C;
+    impp.macro_num=0;
 
-    ldpc_encoder_optim_8seg(harq_process->c,harq_process->d,*pz,Kb,Kr,BG,harq_process->C,NULL,NULL,NULL,NULL);
+    nrLDPC_encoder(harq_process->c,harq_process->d,*pz,Kb,Kr,BG,&impp);
 
     //stop_meas(te_stats);
     //printf("end ldpc encoder -- output\n");
diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h
index 3bca1138c0c0af16df999b18ff404cbb02176d34..d9a57c60ed05ada358bb2db09f16741ea9973cea 100644
--- a/openair1/PHY/defs_gNB.h
+++ b/openair1/PHY/defs_gNB.h
@@ -40,7 +40,7 @@
 #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
 #include "PHY/impl_defs_top.h"
 #include "PHY/defs_common.h"
-#include "PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h"
+#include "PHY/CODING/nrLDPC_extern.h"
 #include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h"
 
 #define MAX_NUM_RU_PER_gNB MAX_NUM_RU_PER_eNB
diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c
index 757ad6f75dea02c3fc1bdec463e44d7f578f1e24..3066f0906fd8a193dffc12e257a4a40424124ae9 100644
--- a/targets/ARCH/COMMON/common_lib.c
+++ b/targets/ARCH/COMMON/common_lib.c
@@ -37,6 +37,7 @@
 #include <stdlib.h>
 
 #include "common_lib.h"
+#include "assertions.h"
 #include "common/utils/load_module_shlib.h"
 #include "common/utils/LOG/log.h"
 #include "targets/RT/USER/lte-softmodem.h"
@@ -91,38 +92,44 @@ int load_lib(openair0_device *device,
 {
   loader_shlibfunc_t shlib_fdesc[1];
   int ret=0;
-  char *libname;
+  char *deflibname=OAI_RF_LIBNAME;
   
   openair0_cfg->recplay_mode = read_recplayconfig(&(openair0_cfg->recplay_conf),&(device->recplay_state));
 
   if ( openair0_cfg->recplay_mode == RECPLAY_REPLAYMODE ) {
-  	  libname=OAI_IQPLAYER_LIBNAME;
+  	  deflibname=OAI_IQPLAYER_LIBNAME;
   	  shlib_fdesc[0].fname="device_init";
   	  set_softmodem_optmask(SOFTMODEM_RECPLAY_BIT);  // softmodem has to know we use the iqplayer to workaround randomized algorithms
   } else  if ( IS_SOFTMODEM_BASICSIM ) {
-	  libname=OAI_BASICSIM_LIBNAME;
+	  deflibname=OAI_BASICSIM_LIBNAME;
 	  shlib_fdesc[0].fname="device_init";
   } else if (IS_SOFTMODEM_RFSIM && flag == RAU_LOCAL_RADIO_HEAD) {
-	  libname=OAI_RFSIM_LIBNAME;
+	  deflibname=OAI_RFSIM_LIBNAME;
 	  shlib_fdesc[0].fname="device_init";
   } else if (flag == RAU_LOCAL_RADIO_HEAD) {
 	  if (IS_SOFTMODEM_RFSIM)
-		  libname="rfsimulator";
+		  deflibname="rfsimulator";
 	  else
-          libname=OAI_RF_LIBNAME;
+          deflibname=OAI_RF_LIBNAME;
       shlib_fdesc[0].fname="device_init";
   } else {
-	  libname=OAI_TP_LIBNAME;
+	  deflibname=OAI_TP_LIBNAME;
 	  shlib_fdesc[0].fname="transport_init";
   }
-  ret=load_module_shlib(libname,shlib_fdesc,1,NULL);
+  
+  char *devname=NULL;
+  paramdef_t device_params[]=DEVICE_PARAMS_DESC ;
+  int numparams = sizeof(device_params)/sizeof(paramdef_t);
+  int devname_pidx = config_paramidx_fromname(device_params,numparams, CONFIG_DEVICEOPT_NAME);
+  device_params[devname_pidx].defstrval=deflibname;
+  
+  config_get(device_params,numparams,DEVICE_SECTION);
+  
+  ret=load_module_shlib(devname,shlib_fdesc,1,NULL);
+  AssertFatal( (ret >= 0),
+  	           "Library %s couldn't be loaded\n",devname);
 
-  if (ret < 0) {
-    LOG_E(HW,"Library %s couldn't be loaded\n",libname);
-  } else {
-    ret=((devfunc_t)shlib_fdesc[0].fptr)(device,openair0_cfg,cfg);
-  }
-  return ret;
+  return ((devfunc_t)shlib_fdesc[0].fptr)(device,openair0_cfg,cfg);
 }
 
 
diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h
index 7e51bdc81a6ad9690f119cfb25b4292ea847960f..ecadb68c0ca7917fc870faf63d6cd88d5835993d 100644
--- a/targets/ARCH/COMMON/common_lib.h
+++ b/targets/ARCH/COMMON/common_lib.h
@@ -448,6 +448,24 @@ typedef struct {
 extern "C"
 {
 #endif
+
+
+#define  DEVICE_SECTION   "device"
+#define  CONFIG_HLP_DEVICE  "Identifies the oai device (the interface to RF) to use, the shared lib \"lib_<name>.so\" will be loaded"
+
+#define  CONFIG_DEVICEOPT_NAME "name"
+
+/* inclusion for device configuration */
+/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
+/*                                            config parameters for oai device                                                                                               */
+/*   optname                     helpstr                paramflags                      XXXptr                  defXXXval                            type           numelt   */
+/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
+#define DEVICE_PARAMS_DESC {\
+    { CONFIG_DEVICEOPT_NAME,      CONFIG_HLP_DEVICE,          0,                strptr:&devname,                 defstrval:NULL,         TYPE_STRING,     0}\
+}
+
+
+
 /*! \brief get device name from device type */
 char *get_devname(int devtype);
 /*! \brief Initialize openair RF target. It returns 0 if OK */
diff --git a/targets/ARCH/COMMON/record_player.h b/targets/ARCH/COMMON/record_player.h
index 903dda006b02e0eb79e1107665220d80090ea225..500acdd709950c167f4513e87b30f65a7f5bb6f7 100644
--- a/targets/ARCH/COMMON/record_player.h
+++ b/targets/ARCH/COMMON/record_player.h
@@ -37,19 +37,6 @@
 extern "C"
 {
 #endif
-#define CONFIG_OPT_RECPLAY "enable_recplay"
-
-#define  CONFIG_HLP_RECPLAY  "Allow record player"
-#define USRP_SECTION "device.usrp"
-/* inclusion for device configuration */
-/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
-/*                                            command line parameters for USRP record/playback                                                                               */
-/*   optname                     helpstr                paramflags                      XXXptr                  defXXXval                            type           numelt   */
-/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
-#define DEVICE_PARAMS_DESC {  \
-    {CONFIG_OPT_RECPLAY,      CONFIG_HLP_RECPLAY, PARAMFLAG_BOOL,   uptr:&enable_recplay,                 defuintval:0,                    TYPE_UINT,     0} \
-  }
-
 
 /* inclusions for record player */
 #define RECPLAY_DISABLED     0
@@ -114,7 +101,7 @@ typedef struct {
     {CONFIG_OPT_SF_LOOPS,     CONFIG_HLP_SF_LOOPS,  0,                uptr:&((*recplay_conf)->u_sf_loops),                defintval:DEF_SF_NB_LOOP,        TYPE_UINT,   0}, \
     {CONFIG_OPT_SF_RDELAY,    CONFIG_HLP_SF_RDELAY, 0,                uptr:&((*recplay_conf)->u_sf_read_delay),           defintval:DEF_SF_DELAY_READ,     TYPE_UINT,   0}, \
     {CONFIG_OPT_SF_WDELAY,    CONFIG_HLP_SF_WDELAY, 0,                uptr:&((*recplay_conf)->u_sf_write_delay),          defintval:DEF_SF_DELAY_WRITE,    TYPE_UINT,   0}, \
-  }/*! \brief USRP Configuration and state */
+  }/*! \brief Record Player Configuration and state */
 typedef struct {
   char            u_sf_filename[1024];              // subframes file path
   unsigned int    u_sf_max ;                  // max number of recorded subframes
diff --git a/targets/ARCH/iqplayer/iqplayer_lib.c b/targets/ARCH/iqplayer/iqplayer_lib.c
index beb05de3fdbf9859f33ad549319bf4ad94def31e..c4133d1b11652615f320065b405f65016ba48970 100644
--- a/targets/ARCH/iqplayer/iqplayer_lib.c
+++ b/targets/ARCH/iqplayer/iqplayer_lib.c
@@ -25,6 +25,7 @@
  */
 #define _LARGEFILE_SOURCE
 #define _FILE_OFFSET_BITS 64
+#define NB_ANTENNAS_RX  2
 #include <string.h>
 #include <pthread.h>
 #include <unistd.h>
@@ -45,7 +46,9 @@
 
 
 static void parse_iqfile_header(openair0_device *device, iqfile_header_t *iq_fh) {
-  AssertFatal((memcmp(iq_fh->oaiid,OAIIQFILE_ID,sizeof(OAIIQFILE_ID)) == 0),"iqfile doesn't seem to be compatible with oai (invalid id in header)\n");
+  AssertFatal((memcmp(iq_fh->oaiid,OAIIQFILE_ID,sizeof(OAIIQFILE_ID)) == 0),
+  	           "iqfile doesn't seem to be compatible with oai (invalid id %.4s in header)\n",
+  	           iq_fh->oaiid);
   device->type = iq_fh->devtype;
   device->openair0_cfg[0].tx_sample_advance=iq_fh->tx_sample_advance;
   device->openair0_cfg[0].tx_bw =  device->openair0_cfg[0].rx_bw = iq_fh->bw;
@@ -138,6 +141,13 @@ static int iqplayer_loadfile(openair0_device *device, openair0_config_t *openair
   return 0;
 }
 
+/*! \brief start the oai iq player
+ * \param device, the hardware used
+ */
+static int trx_iqplayer_start(openair0_device *device){
+	return 0;
+}
+
 /*! \brief Terminate operation of the oai iq player
  * \param device, the hardware used
  */
@@ -287,7 +297,7 @@ static int trx_iqplayer_read(openair0_device *device, openair0_timestamp *ptimes
 
 int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
   device->openair0_cfg = openair0_cfg;
-  device->trx_start_func = NULL;
+  device->trx_start_func = trx_iqplayer_start;
   device->trx_get_stats_func = NULL;
   device->trx_reset_stats_func = NULL;
   device->trx_end_func   = trx_iqplayer_end;
diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c
index fa08d96b5f8a6c88ef376a178d18948588f2559e..e6364cad237799bbb81d0c0b781e3a965beb851c 100644
--- a/targets/RT/USER/lte-ru.c
+++ b/targets/RT/USER/lte-ru.c
@@ -2194,7 +2194,9 @@ int start_rf(RU_t *ru) {
 }
 
 int stop_rf(RU_t *ru) {
-  ru->rfdevice.trx_end_func(&ru->rfdevice);
+    if(ru->rfdevice.trx_end_func != NULL) {
+      ru->rfdevice.trx_end_func(&ru->rfdevice);
+    }
   return 0;
 }