text: /*
      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
      \brief: load library implementing coding/decoding algorithms
      \author Francois TABURET
      \date 2017
      \version 0.1
      \company NOKIA BellLabs France
      \email: francois.taburet@nokia-bell-labs.com
      \note
      \warning
  */
  #define _GNU_SOURCE
  #include <sys/types.h>
  
  
  #include "PHY/defs_common.h"
  #include "PHY/phy_extern.h"
  #include "PHY/CODING/coding_extern.h"
  #include "common/utils/load_module_shlib.h"
  #include "common/utils/telnetsrv/telnetsrv.h"
  
  static int coding_setmod_cmd(char *buff, int debug, telnet_printfunc_t prnt);
  static telnetshell_cmddef_t coding_cmdarray[] =
  {
      {"mode", "[sse,avx2,stdc,none]", coding_setmod_cmd},
      {"", "", NULL},
  };
  telnetshell_vardef_t coding_vardef[] =
  {
      {"maxiter", TELNET_VARTYPE_INT32, &max_turbo_iterations},
      {"", 0, NULL}
  };
  /* PHY/defs.h contains MODE_DECODE_XXX macros, following table must match */
  static char *modedesc[] = {"none", "sse", "C", "avx2"};
  static int curmode;
  /* function description array, to be used when loading the encoding/decoding shared lib */
  loader_shlibfunc_t shlib_fdesc[DECODE_NUM_FPTR];
  
  /* encoding decoding functions pointers, filled here and used when encoding/decoding */
  /*defined as extern in PHY?CODING/extern.h */
  decoder_if_t    *decoder16;
  decoder_if_t    *decoder8;
  encoder_if_t    *encoder;
  
  extern int _may_i_use_cpu_feature(unsigned __int64);
  uint8_t  nodecod(int16_t *y,
                   int16_t *y2,
                   uint8_t *decoded_bytes,
                   uint8_t *decoded_bytes2,
                   uint16_t n,
                   uint8_t max_iterations,
                   uint8_t crc_type,
                   uint8_t F,
                   time_stats_t *init_stats,
                   time_stats_t *alpha_stats,
                   time_stats_t *beta_stats,
                   time_stats_t *gamma_stats,
                   time_stats_t *ext_stats,
                   time_stats_t *intl1_stats,
                   time_stats_t *intl2_stats)
  {
      return max_iterations + 1;
  };
  
  void decoding_setmode(int mode)
  {
      switch(mode)
      {
          case MODE_DECODE_NONE:
              decoder8 = nodecod;
              decoder16 = nodecod;
              encoder = (encoder_if_t *)shlib_fdesc[ENCODE_C_FPTRIDX].fptr;
              break;
          case MODE_DECODE_C:
              decoder16 = (decoder_if_t *)shlib_fdesc[DECODE_TD_C_FPTRIDX].fptr;
              decoder8 = (decoder_if_t *)shlib_fdesc[DECODE_TD_C_FPTRIDX].fptr;
              encoder = (encoder_if_t *)shlib_fdesc[ENCODE_C_FPTRIDX].fptr;
              break;
          case MODE_DECODE_AVX2:
              decoder16 = (decoder_if_t *)shlib_fdesc[DECODE_TD16_AVX2_FPTRIDX].fptr;
              decoder8 = (decoder_if_t *)shlib_fdesc[DECODE_TD8_SSE_FPTRIDX].fptr;
              encoder = (encoder_if_t *)shlib_fdesc[ENCODE_SSE_FPTRIDX].fptr;
              break;
          default:
              mode = MODE_DECODE_SSE;
          case MODE_DECODE_SSE:
              decoder8 = (decoder_if_t *)shlib_fdesc[DECODE_TD8_SSE_FPTRIDX].fptr;
              decoder16 = (decoder_if_t *)shlib_fdesc[DECODE_TD16_SSE_FPTRIDX].fptr;
              encoder = (encoder_if_t *)shlib_fdesc[ENCODE_SSE_FPTRIDX].fptr;
              break;
      }
      curmode = mode;
  }
  
  
  int load_codinglib(void)
  {
      int ret;
  
      memset(shlib_fdesc, 0, sizeof(shlib_fdesc));
      shlib_fdesc[DECODE_INITTD8_SSE_FPTRIDX].fname = "init_td8";
      shlib_fdesc[DECODE_INITTD16_SSE_FPTRIDX].fname = "init_td16";
      shlib_fdesc[DECODE_INITTD_AVX2_FPTRIDX].fname = "init_td16avx2";
  
      shlib_fdesc[DECODE_TD8_SSE_FPTRIDX].fname =   "phy_threegpplte_turbo_decoder8";
      shlib_fdesc[DECODE_TD16_SSE_FPTRIDX].fname =  "phy_threegpplte_turbo_decoder16";
      shlib_fdesc[DECODE_TD_C_FPTRIDX].fname =      "phy_threegpplte_turbo_decoder_scalar";
      shlib_fdesc[DECODE_TD16_AVX2_FPTRIDX].fname = "phy_threegpplte_turbo_decoder16avx2";
  
  
      shlib_fdesc[DECODE_FREETD8_FPTRIDX].fname =    "free_td8";
      shlib_fdesc[DECODE_FREETD16_FPTRIDX].fname =    "free_td16";
      shlib_fdesc[DECODE_FREETD_AVX2_FPTRIDX].fname = "free_td16avx2";
  
      shlib_fdesc[ENCODE_SSE_FPTRIDX].fname =    "threegpplte_turbo_encoder_sse";
      shlib_fdesc[ENCODE_C_FPTRIDX].fname =      "threegpplte_turbo_encoder";
      shlib_fdesc[ENCODE_INIT_SSE_FPTRIDX].fname =       "init_encoder_sse";
      ret = load_module_shlib("coding", shlib_fdesc, DECODE_NUM_FPTR, NULL);
      if(ret < 0)
      {
          exit_fun("Error loading coding library");
      }
  
      /* execute encoder/decoder init functions */
      shlib_fdesc[DECODE_INITTD8_SSE_FPTRIDX].fptr();
      shlib_fdesc[DECODE_INITTD16_SSE_FPTRIDX].fptr();
      if(shlib_fdesc[DECODE_INITTD_AVX2_FPTRIDX].fptr != NULL)
      {
          shlib_fdesc[DECODE_INITTD_AVX2_FPTRIDX].fptr();
      }
      if(shlib_fdesc[ENCODE_INIT_SSE_FPTRIDX].fptr != NULL)
      {
          shlib_fdesc[ENCODE_INIT_SSE_FPTRIDX].fptr();
      }
      decoding_setmode(MODE_DECODE_SSE);
      /* look for telnet server, if it is loaded, add the coding commands to it */
      add_telnetcmd_func_t addcmd = (add_telnetcmd_func_t)get_shlibmodule_fptr("telnetsrv", TELNET_ADDCMD_FNAME);
      if(addcmd != NULL)
      {
          addcmd("coding", coding_vardef, coding_cmdarray);
      }
      return 0;
  }
  
  void free_codinglib(void)
  {
  
      shlib_fdesc[DECODE_FREETD8_FPTRIDX].fptr();
      shlib_fdesc[DECODE_FREETD16_FPTRIDX].fptr();
      shlib_fdesc[DECODE_FREETD_AVX2_FPTRIDX].fptr();
  
  
  }
  
  /* functions for telnet support, when telnet server is loaded */
  int coding_setmod_cmd(char *buff, int debug, telnet_printfunc_t prnt)
  {
      if(debug > 0)
      {
          prnt("coding_setmod_cmd received %s\n", buff);
      }
  
      if(strcasestr(buff, "sse") != NULL)
      {
          decoding_setmode(MODE_DECODE_SSE);
      }
      else if(strcasestr(buff, "avx2") != NULL)
      {
          decoding_setmode(MODE_DECODE_AVX2);
      }
      else if(strcasestr(buff, "stdc") != NULL)
      {
          decoding_setmode(MODE_DECODE_C);
      }
      else if(strcasestr(buff, "none") != NULL)
      {
          decoding_setmode(MODE_DECODE_NONE);
      }
      else
      {
          prnt("%s: wrong setmod parameter...\n", buff);
      }
      prnt("Coding and decoding current mode: %s\n", modedesc[curmode]);
      return 0;
  }
  