Skip to content
Snippets Groups Projects
nfapi_pnf.c 63.2 KiB
Newer Older
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>

#include "debug.h"
#include "nfapi_pnf_interface.h"
#include "nfapi.h"
#include "nfapi_pnf.h"
#include "common/ran_context.h"
#include "openair2/PHY_INTERFACE/phy_stub_UE.h"
//#include "openair1/PHY/vars.h"
extern RAN_CONTEXT_t RC;

#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <assert.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <errno.h>

#include <vendor_ext.h>
#include "fapi_stub.h"
#define _GNU_SOURCE

extern void phy_init_RU(RU_t*);
extern pthread_cond_t nfapi_sync_cond;
extern pthread_mutex_t nfapi_sync_mutex;
extern int nfapi_sync_var;

extern int sync_var;
extern void init_UE_stub(int nb_inst,int,int);
extern void handle_nfapi_dci_dl_pdu(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, nfapi_dl_config_request_pdu_t *dl_config_pdu);
extern void handle_nfapi_ul_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, nfapi_ul_config_request_pdu_t *ul_config_pdu, uint16_t frame,uint8_t subframe,uint8_t srs_present);
extern void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,  nfapi_dl_config_request_pdu_t *dl_config_pdu, uint8_t codeword_index, uint8_t *sdu);
extern void handle_nfapi_hi_dci0_dci_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, nfapi_hi_dci0_request_pdu_t *hi_dci0_config_pdu);
extern void handle_nfapi_hi_dci0_hi_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, nfapi_hi_dci0_request_pdu_t *hi_dci0_config_pdu);
extern void handle_nfapi_bch_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, nfapi_dl_config_request_pdu_t *dl_config_pdu, uint8_t *sdu);
extern uint8_t  nfapi_mode;

nfapi_tx_request_pdu_t* tx_request_pdu[1023][10][10]; // [frame][subframe][max_num_pdus]
uint16_t phy_antenna_capability_values[] = { 1, 2, 4, 8, 16 };

nfapi_pnf_param_response_t g_pnf_param_resp;


nfapi_pnf_p7_config_t *p7_config_g = NULL;

void* pnf_allocate(size_t size)
{
  //DJP
  //return (void*)memory_pool::allocate(size);
  return malloc(size);
}

void pnf_deallocate(void* ptr)
{
  //DJP
  //memory_pool::deallocate((uint8_t*)ptr);
  free(ptr);
}


//class udp_data
//DJP
typedef struct 
{
  //public:
  uint8_t enabled;
  uint32_t rx_port;
  uint32_t tx_port;
  //std::string tx_addr;
  char tx_addr[80];
}udp_data;

//class phy_info
//DJP
typedef struct 
{
#if 0
  public:

    phy_info()
      : first_subframe_ind(0), fapi(0),
      dl_ues_per_subframe(0), ul_ues_per_subframe(0), 
      timing_window(0), timing_info_mode(0), timing_info_period(0)
  {
    index = 0;
    id = 0;

    local_port = 0;
    remote_addr = 0;
    remote_port = 0;

    duplex_mode = 0;
    dl_channel_bw_support = 0;
    ul_channel_bw_support = 0;
    num_dl_layers_supported = 0;
    num_ul_layers_supported = 0;
    release_supported = 0;
    nmm_modes_supported = 0;
  }
#endif

    uint16_t index;
    uint16_t id;
    //std::vector<uint8_t> rfs;
    //std::vector<uint8_t> excluded_rfs;
    uint8_t rfs[2];
    uint8_t excluded_rfs[2];

    udp_data udp;

    //std::string local_addr;
    char local_addr[80];
    int local_port;

    char* remote_addr;
    int remote_port;

    uint8_t duplex_mode;
    uint16_t dl_channel_bw_support;
    uint16_t ul_channel_bw_support;
    uint8_t num_dl_layers_supported;
    uint8_t num_ul_layers_supported;
    uint16_t release_supported;
    uint8_t nmm_modes_supported;

    uint8_t dl_ues_per_subframe;
    uint8_t ul_ues_per_subframe;

    uint8_t first_subframe_ind;

    // timing information recevied from the vnf
    uint8_t timing_window;
    uint8_t timing_info_mode;
    uint8_t timing_info_period;

    //fapi_t* fapi;

}phy_info;

//class rf_info
//DJP
typedef struct 
{
  //public:
  uint16_t index;
  uint16_t band;
  int16_t max_transmit_power;
  int16_t min_transmit_power;
  uint8_t num_antennas_supported;
  uint32_t min_downlink_frequency;
  uint32_t max_downlink_frequency;
  uint32_t max_uplink_frequency;
  uint32_t min_uplink_frequency;
}rf_info;


//class pnf_info
//DJP
typedef struct 
{
#if 0
  public:

    pnf_info() 
      : release(13), wireshark_test_mode(0),
      max_total_power(0), oui(0)

  {
    release = 0;

    sync_mode = 0;
    location_mode = 0;
    dl_config_timing = 0;
    ul_config_timing = 0;
    tx_timing = 0;
    hi_dci0_timing = 0;

    max_phys = 0;
    max_total_bw = 0;
    max_total_dl_layers = 0;
    max_total_ul_layers = 0;
    shared_bands = 0;
    shared_pa = 0;

  }
#endif

    int release;
    //DJPstd::vector<phy_info> phys;
    //std::vector<rf_info> rfs;
    phy_info phys[2];
    rf_info rfs[2];

    uint8_t sync_mode;
    uint8_t location_mode;
    uint8_t location_coordinates[6];
    uint32_t dl_config_timing;
    uint32_t ul_config_timing;
    uint32_t tx_timing;
    uint32_t hi_dci0_timing;

    uint16_t max_phys;
    uint16_t max_total_bw;
    uint16_t max_total_dl_layers;
    uint16_t max_total_ul_layers;
    uint8_t shared_bands;
    uint8_t shared_pa;
    int16_t max_total_power;
    uint8_t oui;

    uint8_t wireshark_test_mode;

}pnf_info;

// DJP struct pnf_phy_user_data_t
typedef struct 
{
  uint16_t phy_id;
  nfapi_pnf_config_t* config;
  phy_info* phy;
  nfapi_pnf_p7_config_t* p7_config;
}pnf_phy_user_data_t;

static pnf_info pnf;
static pthread_t pnf_start_pthread;

extern void nfapi_log(char *file, char *func, int line, int comp, int level, const char* format, va_list args);

void pnf_nfapi_trace(nfapi_trace_level_t nfapi_level, const char* message, ...)

  va_list    args;
  int oai_level;

  if (nfapi_level==NFAPI_TRACE_ERROR)
  {
    oai_level = LOG_ERR;
  }
  else if (nfapi_level==NFAPI_TRACE_WARN)
  {
    oai_level = LOG_WARNING;
  }
  else if (nfapi_level==NFAPI_TRACE_NOTE)
  {
    oai_level = LOG_INFO;
  }
  else if (nfapi_level==NFAPI_TRACE_INFO)
  {
    oai_level = LOG_INFO;
  }
  else
  {
    oai_level = LOG_INFO;
  }

  va_start(args, message);
  nfapi_log("FILE>", "FUNC", 999, PHY, oai_level, message, args);
  va_end(args);
  #else
  va_list    args;
  va_start(args, message);
  vprintf(message, args);
  va_end(args);
}

void pnf_set_thread_priority(int priority)
{
  //printf("%s(priority:%d)\n", __FUNCTION__, priority);

  pthread_attr_t ptAttr;

  struct sched_param schedParam;
  schedParam.__sched_priority = priority; //79;
  if(sched_setscheduler(0, SCHED_RR, &schedParam) != 0)
  {
    printf("failed to set SCHED_RR\n");
  }

  if(pthread_attr_setschedpolicy(&ptAttr, SCHED_RR) != 0)
  {
    printf("failed to set pthread SCHED_RR %d\n", errno);
  }

  pthread_attr_setinheritsched(&ptAttr, PTHREAD_EXPLICIT_SCHED);

  struct sched_param thread_params;
  thread_params.sched_priority = 20;
  if(pthread_attr_setschedparam(&ptAttr, &thread_params) != 0)
  {
    printf("failed to set sched param\n");
  }
}

void* pnf_p7_thread_start(void* ptr)
{
  NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] P7 THREAD %s\n", __FUNCTION__);

  pnf_set_thread_priority(79);

  nfapi_pnf_p7_config_t* config = (nfapi_pnf_p7_config_t*)ptr;
  nfapi_pnf_p7_start(config);

  return 0;
}



int pnf_param_request(nfapi_pnf_config_t* config, nfapi_pnf_param_request_t* req)
{
  printf("[PNF] pnf param request\n");

  nfapi_pnf_param_response_t resp;
  memset(&resp, 0, sizeof(resp));
  resp.header.message_id = NFAPI_PNF_PARAM_RESPONSE;
  resp.error_code = NFAPI_MSG_OK;

  pnf_info* pnf = (pnf_info*)(config->user_data);

  resp.pnf_param_general.tl.tag = NFAPI_PNF_PARAM_GENERAL_TAG;
  resp.pnf_param_general.nfapi_sync_mode = pnf->sync_mode;
  resp.pnf_param_general.location_mode = pnf->location_mode;
  //uint8_t location_coordinates[NFAPI_PNF_PARAM_GENERAL_LOCATION_LENGTH];
  resp.pnf_param_general.dl_config_timing = pnf->dl_config_timing;
  resp.pnf_param_general.tx_timing = pnf->tx_timing;
  resp.pnf_param_general.ul_config_timing = pnf->ul_config_timing;
  resp.pnf_param_general.hi_dci0_timing = pnf->hi_dci0_timing;
  resp.pnf_param_general.maximum_number_phys = pnf->max_phys;
  resp.pnf_param_general.maximum_total_bandwidth = pnf->max_total_bw;
  resp.pnf_param_general.maximum_total_number_dl_layers = pnf->max_total_dl_layers;
  resp.pnf_param_general.maximum_total_number_ul_layers = pnf->max_total_ul_layers;
  resp.pnf_param_general.shared_bands = pnf->shared_bands;
  resp.pnf_param_general.shared_pa = pnf->shared_pa;
  resp.pnf_param_general.maximum_total_power = pnf->max_total_power;
  //uint8_t oui[NFAPI_PNF_PARAM_GENERAL_OUI_LENGTH];

  resp.pnf_phy.tl.tag = NFAPI_PNF_PHY_TAG;
  //DJP resp.pnf_phy.number_of_phys = pnf->phys.size();
  resp.pnf_phy.number_of_phys = 1;

  //for(int i = 0; i < pnf->phys.size(); ++i)
  for(int i = 0; i < 1; ++i)
  {
    resp.pnf_phy.phy[i].phy_config_index = pnf->phys[i].index; 
    resp.pnf_phy.phy[i].downlink_channel_bandwidth_supported = pnf->phys[i].dl_channel_bw_support;
    resp.pnf_phy.phy[i].uplink_channel_bandwidth_supported = pnf->phys[i].ul_channel_bw_support;
    resp.pnf_phy.phy[i].number_of_dl_layers_supported = pnf->phys[i].num_dl_layers_supported;
    resp.pnf_phy.phy[i].number_of_ul_layers_supported = pnf->phys[i].num_ul_layers_supported;
    resp.pnf_phy.phy[i].maximum_3gpp_release_supported = pnf->phys[i].release_supported;
    resp.pnf_phy.phy[i].nmm_modes_supported = pnf->phys[i].nmm_modes_supported;

    //DJP resp.pnf_phy.phy[i].number_of_rfs = pnf->phys[i].rfs.size();
    resp.pnf_phy.phy[i].number_of_rfs = 2;
    //for(int j = 0; j < pnf->phys[i].rfs.size(); ++j)
    for(int j = 0; j < 1; ++j)
    {
      resp.pnf_phy.phy[i].rf_config[j].rf_config_index = pnf->phys[i].rfs[j];
    }

    //DJP resp.pnf_phy.phy[i].number_of_rf_exclusions = pnf->phys[i].excluded_rfs.size();
    resp.pnf_phy.phy[i].number_of_rf_exclusions = 0;
    //DJP for(int j = 0; j < pnf->phys[i].excluded_rfs.size(); ++j)
    for(int j = 0; j < 0; ++j)
    {
      resp.pnf_phy.phy[i].excluded_rf_config[j].rf_config_index = pnf->phys[i].excluded_rfs[j];
    }
  }


  resp.pnf_rf.tl.tag = NFAPI_PNF_RF_TAG;
  //DJPresp.pnf_rf.number_of_rfs = pnf->rfs.size();
  resp.pnf_rf.number_of_rfs = 2;

  //for(int i = 0; i < pnf->rfs.size(); ++i)
  for(int i = 0; i < 2; ++i)
  {
    resp.pnf_rf.rf[i].rf_config_index = pnf->rfs[i].index; 
    resp.pnf_rf.rf[i].band = pnf->rfs[i].band;
    resp.pnf_rf.rf[i].maximum_transmit_power = pnf->rfs[i].max_transmit_power; 
    resp.pnf_rf.rf[i].minimum_transmit_power = pnf->rfs[i].min_transmit_power;
    resp.pnf_rf.rf[i].number_of_antennas_suppported = pnf->rfs[i].num_antennas_supported;
    resp.pnf_rf.rf[i].minimum_downlink_frequency = pnf->rfs[i].min_downlink_frequency;
    resp.pnf_rf.rf[i].maximum_downlink_frequency = pnf->rfs[i].max_downlink_frequency;
    resp.pnf_rf.rf[i].minimum_uplink_frequency = pnf->rfs[i].min_uplink_frequency;
    resp.pnf_rf.rf[i].maximum_uplink_frequency = pnf->rfs[i].max_uplink_frequency;
  }

  if(pnf->release >= 10)
  {
    resp.pnf_phy_rel10.tl.tag = NFAPI_PNF_PHY_REL10_TAG;
    //DJPresp.pnf_phy_rel10.number_of_phys = pnf->phys.size();
    resp.pnf_phy_rel10.number_of_phys = 1;

    //for(int i = 0; i < pnf->phys.size(); ++i)
    for(int i = 0; i < 1; ++i)
    {
      resp.pnf_phy_rel10.phy[i].phy_config_index = pnf->phys[i].index; 
      resp.pnf_phy_rel10.phy[i].transmission_mode_7_supported = 0;
      resp.pnf_phy_rel10.phy[i].transmission_mode_8_supported = 1;
      resp.pnf_phy_rel10.phy[i].two_antenna_ports_for_pucch = 0;
      resp.pnf_phy_rel10.phy[i].transmission_mode_9_supported = 1;
      resp.pnf_phy_rel10.phy[i].simultaneous_pucch_pusch = 0;
      resp.pnf_phy_rel10.phy[i].four_layer_tx_with_tm3_and_tm4 = 1;

    }
  }

  if(pnf->release >= 11)
  {
    resp.pnf_phy_rel11.tl.tag = NFAPI_PNF_PHY_REL11_TAG;
    //DJP resp.pnf_phy_rel11.number_of_phys = pnf->phys.size();
    resp.pnf_phy_rel11.number_of_phys = 1;

    //DJP for(int i = 0; i < pnf->phys.size(); ++i)
    for(int i = 0; i < 1; ++i)
    {
      resp.pnf_phy_rel11.phy[i].phy_config_index = pnf->phys[i].index; 
      resp.pnf_phy_rel11.phy[i].edpcch_supported = 0;
      resp.pnf_phy_rel11.phy[i].multi_ack_csi_reporting = 1;
      resp.pnf_phy_rel11.phy[i].pucch_tx_diversity = 0;
      resp.pnf_phy_rel11.phy[i].ul_comp_supported = 1;
      resp.pnf_phy_rel11.phy[i].transmission_mode_5_supported = 0;
    }
  }

  if(pnf->release >= 12)
  {
    resp.pnf_phy_rel12.tl.tag = NFAPI_PNF_PHY_REL12_TAG;
    //DJP resp.pnf_phy_rel12.number_of_phys = pnf->phys.size();
    resp.pnf_phy_rel12.number_of_phys = 1;

    //DJP for(int i = 0; i < pnf->phys.size(); ++i)
    for(int i = 0; i < 1; ++i)
    {
      resp.pnf_phy_rel12.phy[i].phy_config_index = pnf->phys[i].index; 
      resp.pnf_phy_rel12.phy[i].csi_subframe_set = 0;
      resp.pnf_phy_rel12.phy[i].enhanced_4tx_codebook = 2; // yes this is invalid
      resp.pnf_phy_rel12.phy[i].drs_supported = 0;
      resp.pnf_phy_rel12.phy[i].ul_64qam_supported = 1;
      resp.pnf_phy_rel12.phy[i].transmission_mode_10_supported = 0;
      resp.pnf_phy_rel12.phy[i].alternative_bts_indices = 1;
    }
  }

  if(pnf->release >= 13)
  {
    resp.pnf_phy_rel13.tl.tag = NFAPI_PNF_PHY_REL13_TAG;
    //DJP resp.pnf_phy_rel13.number_of_phys = pnf->phys.size();
    resp.pnf_phy_rel13.number_of_phys = 1;

    //for(int i = 0; i < pnf->phys.size(); ++i)
    for(int i = 0; i < 1; ++i)
    {
      resp.pnf_phy_rel13.phy[i].phy_config_index = pnf->phys[i].index; 
      resp.pnf_phy_rel13.phy[i].pucch_format4_supported = 0;
      resp.pnf_phy_rel13.phy[i].pucch_format5_supported = 1;
      resp.pnf_phy_rel13.phy[i].more_than_5_ca_support = 0;
      resp.pnf_phy_rel13.phy[i].laa_supported = 1;
      resp.pnf_phy_rel13.phy[i].laa_ending_in_dwpts_supported = 0;
      resp.pnf_phy_rel13.phy[i].laa_starting_in_second_slot_supported = 1;
      resp.pnf_phy_rel13.phy[i].beamforming_supported = 0;
      resp.pnf_phy_rel13.phy[i].csi_rs_enhancement_supported = 1;
      resp.pnf_phy_rel13.phy[i].drms_enhancement_supported = 0;
      resp.pnf_phy_rel13.phy[i].srs_enhancement_supported = 1;
    }

    resp.pnf_phy_rel13_nb_iot.tl.tag = NFAPI_PNF_PHY_REL13_NB_IOT_TAG;
    //DJP resp.pnf_phy_rel13_nb_iot.number_of_phys = pnf->phys.size();		
    resp.pnf_phy_rel13_nb_iot.number_of_phys = 1;

    //for(int i = 0; i < pnf->phys.size(); ++i)
    for(int i = 0; i < 1; ++i)
    {
      resp.pnf_phy_rel13_nb_iot.phy[i].phy_config_index = pnf->phys[i].index; 

      //DJP resp.pnf_phy_rel13_nb_iot.phy[i].number_of_rfs = pnf->phys[i].rfs.size();
      resp.pnf_phy_rel13_nb_iot.phy[i].number_of_rfs = 1;
      //DJP for(int j = 0; j < pnf->phys[i].rfs.size(); ++j)
      for(int j = 0; j < 1; ++j)
      {
        resp.pnf_phy_rel13_nb_iot.phy[i].rf_config[j].rf_config_index = pnf->phys[i].rfs[j];
      }

      //DJP resp.pnf_phy_rel13_nb_iot.phy[i].number_of_rf_exclusions = pnf->phys[i].excluded_rfs.size();
      resp.pnf_phy_rel13_nb_iot.phy[i].number_of_rf_exclusions = 1;
      //DJP for(int j = 0; j < pnf->phys[i].excluded_rfs.size(); ++j)
      for(int j = 0; j < 1; ++j)
      {
        resp.pnf_phy_rel13_nb_iot.phy[i].excluded_rf_config[j].rf_config_index = pnf->phys[i].excluded_rfs[j];
      }

      resp.pnf_phy_rel13_nb_iot.phy[i].number_of_dl_layers_supported = pnf->phys[i].num_dl_layers_supported;
      resp.pnf_phy_rel13_nb_iot.phy[i].number_of_ul_layers_supported = pnf->phys[i].num_ul_layers_supported;
      resp.pnf_phy_rel13_nb_iot.phy[i].maximum_3gpp_release_supported = pnf->phys[i].release_supported;
      resp.pnf_phy_rel13_nb_iot.phy[i].nmm_modes_supported = pnf->phys[i].nmm_modes_supported;

    }
  }


  nfapi_pnf_pnf_param_resp(config, &resp);

  return 0;
}

int pnf_config_request(nfapi_pnf_config_t* config, nfapi_pnf_config_request_t* req)
{
  printf("[PNF] pnf config request\n");

  pnf_info* pnf = (pnf_info*)(config->user_data);

#if 0
  for(int i = 0; i < req->pnf_phy_rf_config.number_phy_rf_config_info; ++i)
  {
    auto found = std::find_if(pnf->phys.begin(), pnf->phys.end(), [&](phy_info& item)
        { return item.index == req->pnf_phy_rf_config.phy_rf_config[i].phy_config_index; });

    if(found != pnf->phys.end())
    {
      phy_info& phy = (*found);
      phy.id = req->pnf_phy_rf_config.phy_rf_config[i].phy_id;
      printf("[PNF] pnf config request assigned phy_id %d to phy_config_index %d\n", phy.id, req->pnf_phy_rf_config.phy_rf_config[i].phy_config_index);
    }
    else
    {
      // did not find the phy
      printf("[PNF] pnf config request did not find phy_config_index %d\n", req->pnf_phy_rf_config.phy_rf_config[i].phy_config_index);
    }

  }
#endif
  //DJP
  phy_info *phy = pnf->phys;
  phy->id = req->pnf_phy_rf_config.phy_rf_config[0].phy_id;
  printf("[PNF] pnf config request assigned phy_id %d to phy_config_index %d\n", phy->id, req->pnf_phy_rf_config.phy_rf_config[0].phy_config_index);
  //DJP

  nfapi_pnf_config_response_t resp;
  memset(&resp, 0, sizeof(resp));
  resp.header.message_id = NFAPI_PNF_CONFIG_RESPONSE;
  resp.error_code = NFAPI_MSG_OK;
  nfapi_pnf_pnf_config_resp(config, &resp);
  printf("[PNF] Sent pnf_config_resp\n");

  return 0;
}

void nfapi_send_pnf_start_resp(nfapi_pnf_config_t* config, uint16_t phy_id)
{
  printf("Sending NFAPI_START_RESPONSE config:%p phy_id:%d\n", config, phy_id);

  nfapi_start_response_t start_resp;
  memset(&start_resp, 0, sizeof(start_resp));
  start_resp.header.message_id = NFAPI_START_RESPONSE;
  start_resp.header.phy_id = phy_id;
  start_resp.error_code = NFAPI_MSG_OK;

  nfapi_pnf_start_resp(config, &start_resp);
}

int pnf_start_request(nfapi_pnf_config_t* config, nfapi_pnf_start_request_t* req)
{
  printf("Received NFAPI_PNF_START_REQUEST\n");

  pnf_info* pnf = (pnf_info*)(config->user_data);

  // start all phys that have been configured
  //for(phy_info& phy : pnf->phys)
  phy_info* phy = pnf->phys;
  if(phy->id != 0)
  {
    //auto found = std::find_if(pnf->phys.begin(), pnf->phys.end(), [&](phy_info& item)
    //		{ return item.id == req->header.phy_id; });
    //
    //	if(found != pnf->phys.end())
    //	{
    //		phy_info& phy = (*found);
    //}

    nfapi_pnf_start_response_t resp;
    memset(&resp, 0, sizeof(resp));
    resp.header.message_id = NFAPI_PNF_START_RESPONSE;
    resp.error_code = NFAPI_MSG_OK;
    nfapi_pnf_pnf_start_resp(config, &resp);
    printf("[PNF] Sent NFAPI_PNF_START_RESP\n");
  }
  return 0;
}

int pnf_stop_request(nfapi_pnf_config_t* config, nfapi_pnf_stop_request_t* req)
{
  printf("[PNF] Received NFAPI_PNF_STOP_REQ\n");

  nfapi_pnf_stop_response_t resp;
  memset(&resp, 0, sizeof(resp));
  resp.header.message_id = NFAPI_PNF_STOP_RESPONSE;
  resp.error_code = NFAPI_MSG_OK;
  nfapi_pnf_pnf_stop_resp(config, &resp);
  printf("[PNF] Sent NFAPI_PNF_STOP_REQ\n");

  return 0;
}

int param_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_param_request_t* req)
{
  printf("[PNF] Received NFAPI_PARAM_REQUEST phy_id:%d\n", req->header.phy_id);

  //pnf_info* pnf = (pnf_info*)(config->user_data);

  nfapi_param_response_t nfapi_resp;

  pnf_info* pnf = (pnf_info*)(config->user_data);

  memset(&nfapi_resp, 0, sizeof(nfapi_resp));
  nfapi_resp.header.message_id = NFAPI_PARAM_RESPONSE;
  nfapi_resp.header.phy_id = req->header.phy_id;
  nfapi_resp.error_code = 0; // DJP - what value???

  struct sockaddr_in pnf_p7_sockaddr;

  pnf_p7_sockaddr.sin_addr.s_addr = inet_addr(pnf->phys[0].local_addr);
  nfapi_resp.nfapi_config.p7_pnf_address_ipv4.tl.tag = NFAPI_NFAPI_P7_PNF_ADDRESS_IPV4_TAG;
  memcpy(nfapi_resp.nfapi_config.p7_pnf_address_ipv4.address, &pnf_p7_sockaddr.sin_addr.s_addr, 4);
  nfapi_resp.num_tlv++;

  // P7 PNF Port
  nfapi_resp.nfapi_config.p7_pnf_port.tl.tag = NFAPI_NFAPI_P7_PNF_PORT_TAG;
  nfapi_resp.nfapi_config.p7_pnf_port.value = 32123; // DJP - hard code alert!!!! FIXME TODO
  nfapi_resp.num_tlv++;

  nfapi_pnf_param_resp(config, &nfapi_resp);

  printf("[PNF] Sent NFAPI_PARAM_RESPONSE phy_id:%d number_of_tlvs:%u\n", req->header.phy_id, nfapi_resp.num_tlv);
#if 0
  //DJP
  auto found = std::find_if(pnf->phys.begin(), pnf->phys.end(), [&](phy_info& item)
      { return item.id == req->header.phy_id; });

  if(found != pnf->phys.end())
#endif
  {
    //DJP phy_info& phy_info = (*found);
    //phy_info *phy_info = pnf->phys;

  }
#if 0
  else
  {
    // did not find the phy
  }
#endif

  printf("[PNF] param request .. exit\n");

  return 0;
}

// From MAC config.c
extern uint32_t from_earfcn(int eutra_bandP,uint32_t dl_earfcn);
extern int32_t get_uldl_offset(int eutra_bandP);

int config_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_config_request_t* req)
{
  printf("[PNF] Received NFAPI_CONFIG_REQ phy_id:%d\n", req->header.phy_id);

  pnf_info* pnf = (pnf_info*)(config->user_data);
  uint8_t num_tlv = 0;
  struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0];
  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;

#if 0
  //DJP
  auto found = std::find_if(pnf->phys.begin(), pnf->phys.end(), [&](phy_info& item)
      { return item.id == req->header.phy_id; });

  if(found != pnf->phys.end())
  {
    phy_info& phy_info = (*found);
  }
#endif
  //DJP 
  phy_info* phy_info = pnf->phys;

  if(req->nfapi_config.timing_window.tl.tag == NFAPI_NFAPI_TIMING_WINDOW_TAG)
  {
    phy_info->timing_window = req->nfapi_config.timing_window.value;
    printf("Phy_info:Timing window:%u NFAPI_CONFIG:timing_window:%u\n", phy_info->timing_window, req->nfapi_config.timing_window.value);
    num_tlv++;
  }

  if(req->nfapi_config.timing_info_mode.tl.tag == NFAPI_NFAPI_TIMING_INFO_MODE_TAG)
  {
    printf("timing info mode:%d\n", req->nfapi_config.timing_info_mode.value);
    phy_info->timing_info_mode = req->nfapi_config.timing_info_mode.value;
    num_tlv++;
  }
  else 
  {
    phy_info->timing_info_mode = 0;
    printf("NO timing info mode provided\n");
  }

  if(req->nfapi_config.timing_info_period.tl.tag == NFAPI_NFAPI_TIMING_INFO_PERIOD_TAG)
  {
    printf("timing info period provided value:%d\n", req->nfapi_config.timing_info_period.value);
    phy_info->timing_info_period = req->nfapi_config.timing_info_period.value;
    num_tlv++;
  }
  else 
  {
    phy_info->timing_info_period = 0;
  }

  if(req->rf_config.dl_channel_bandwidth.tl.tag == NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG)
  {
    phy_info->dl_channel_bw_support = req->rf_config.dl_channel_bandwidth.value;
    fp->N_RB_DL = req->rf_config.dl_channel_bandwidth.value;
    NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG N_RB_DL:%u\n", __FUNCTION__, fp->N_RB_DL);
  }
  else
  {
    NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() Missing NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG\n", __FUNCTION__);
  }

  if(req->rf_config.ul_channel_bandwidth.tl.tag == NFAPI_RF_CONFIG_UL_CHANNEL_BANDWIDTH_TAG)
  {
    phy_info->ul_channel_bw_support = req->rf_config.ul_channel_bandwidth.value;
    fp->N_RB_UL = req->rf_config.ul_channel_bandwidth.value;
    num_tlv++;
  }

  if(req->nfapi_config.rf_bands.tl.tag == NFAPI_NFAPI_RF_BANDS_TAG)
  {
    pnf->rfs[0].band = req->nfapi_config.rf_bands.rf_band[0];
    fp->eutra_band = req->nfapi_config.rf_bands.rf_band[0];
    num_tlv++;
  }

  if(req->nfapi_config.earfcn.tl.tag == NFAPI_NFAPI_EARFCN_TAG)
  {
    fp->dl_CarrierFreq = from_earfcn(fp->eutra_band, req->nfapi_config.earfcn.value); // DJP - TODO FIXME - hard coded to first rf
    fp->ul_CarrierFreq = fp->dl_CarrierFreq - (get_uldl_offset(fp->eutra_band) * 1e5);
    num_tlv++;

    NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() earfcn:%u dl_carrierFreq:%u ul_CarrierFreq:%u band:%u N_RB_DL:%u\n", 
        __FUNCTION__, req->nfapi_config.earfcn.value, fp->dl_CarrierFreq, fp->ul_CarrierFreq, pnf->rfs[0].band, fp->N_RB_DL);
  }

  if (req->subframe_config.duplex_mode.tl.tag == NFAPI_SUBFRAME_CONFIG_DUPLEX_MODE_TAG)
  {
    fp->frame_type = req->subframe_config.duplex_mode.value==0 ? TDD : FDD;
    NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() frame_type:%d\n", __FUNCTION__, fp->frame_type);
  }
  if (req->subframe_config.dl_cyclic_prefix_type.tl.tag == NFAPI_SUBFRAME_CONFIG_DL_CYCLIC_PREFIX_TYPE_TAG)
  {
    fp->Ncp = req->subframe_config.dl_cyclic_prefix_type.value;
    num_tlv++;
  }

  if (req->subframe_config.ul_cyclic_prefix_type.tl.tag == NFAPI_SUBFRAME_CONFIG_UL_CYCLIC_PREFIX_TYPE_TAG)
  {
    fp->Ncp_UL = req->subframe_config.ul_cyclic_prefix_type.value;
  fp->num_MBSFN_config = 0; // DJP - hard code alert

  if (req->sch_config.physical_cell_id.tl.tag == NFAPI_SCH_CONFIG_PHYSICAL_CELL_ID_TAG)
  {
    fp->Nid_cell = req->sch_config.physical_cell_id.value;
    fp->nushift = fp->Nid_cell%6;
    num_tlv++;
  }

  if (req->rf_config.tx_antenna_ports.tl.tag == NFAPI_RF_CONFIG_TX_ANTENNA_PORTS_TAG)
  {
    fp->nb_antennas_tx = req->rf_config.tx_antenna_ports.value;
    fp->nb_antenna_ports_eNB = 1;
    num_tlv++;
  }

  if (req->rf_config.rx_antenna_ports.tl.tag == NFAPI_RF_CONFIG_RX_ANTENNA_PORTS_TAG)
  {
    fp->nb_antennas_rx = req->rf_config.rx_antenna_ports.value;
    num_tlv++;
  }

  if (req->phich_config.phich_resource.tl.tag == NFAPI_PHICH_CONFIG_PHICH_RESOURCE_TAG)
  {
    fp->phich_config_common.phich_resource = req->phich_config.phich_resource.value;
    num_tlv++;
  }

  if (req->phich_config.phich_duration.tl.tag == NFAPI_PHICH_CONFIG_PHICH_DURATION_TAG)
  {
    fp->phich_config_common.phich_duration = req->phich_config.phich_duration.value;
    num_tlv++;
  }

  if (req->phich_config.phich_power_offset.tl.tag == NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG)
  {
    LOG_E(PHY, "%s() NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG tag:%d not supported\n", __FUNCTION__, req->phich_config.phich_power_offset.tl.tag);
    //fp->phich_config_common.phich_power_offset = req->phich_config.
    num_tlv++;
  }

  // UL RS Config
  if (req->uplink_reference_signal_config.cyclic_shift_1_for_drms.tl.tag == NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_CYCLIC_SHIFT_1_FOR_DRMS_TAG)
  {
    fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = req->uplink_reference_signal_config.cyclic_shift_1_for_drms.value;
    num_tlv++;
  }

  if (req->uplink_reference_signal_config.uplink_rs_hopping.tl.tag == NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_UPLINK_RS_HOPPING_TAG)
  {
    fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = req->uplink_reference_signal_config.uplink_rs_hopping.value;
    num_tlv++;
  }

  if (req->uplink_reference_signal_config.group_assignment.tl.tag == NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_GROUP_ASSIGNMENT_TAG)
  {
    fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = req->uplink_reference_signal_config.group_assignment.value;
    num_tlv++;
  }

  if (req->pusch_config.hopping_mode.tl.tag == NFAPI_PUSCH_CONFIG_HOPPING_MODE_TAG) { }  // DJP - not being handled?

  fp->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 0; // DJP - not being handled

  if (req->prach_config.configuration_index.tl.tag == NFAPI_PRACH_CONFIG_CONFIGURATION_INDEX_TAG)
  {
    fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex=req->prach_config.configuration_index.value;
    num_tlv++;
  }

  if (req->prach_config.root_sequence_index.tl.tag == NFAPI_PRACH_CONFIG_ROOT_SEQUENCE_INDEX_TAG)
  {
    fp->prach_config_common.rootSequenceIndex=req->prach_config.root_sequence_index.value;
    num_tlv++;
  }

  if (req->prach_config.zero_correlation_zone_configuration.tl.tag == NFAPI_PRACH_CONFIG_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG)
  {
    fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig=req->prach_config.zero_correlation_zone_configuration.value;
    num_tlv++;
  }

  if (req->prach_config.high_speed_flag.tl.tag == NFAPI_PRACH_CONFIG_HIGH_SPEED_FLAG_TAG)
  {
    fp->prach_config_common.prach_ConfigInfo.highSpeedFlag=req->prach_config.high_speed_flag.value;
    num_tlv++;
  }

  if (req->prach_config.frequency_offset.tl.tag == NFAPI_PRACH_CONFIG_FREQUENCY_OFFSET_TAG)
  {
    fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset=req->prach_config.frequency_offset.value;
    num_tlv++;
  }

  printf("[PNF] CONFIG_REQUEST[num_tlv:%d] TLVs processed:%d\n", req->num_tlv, num_tlv);

  printf("[PNF] Simulating PHY CONFIG - DJP\n");
  PHY_Config_t phy_config;
  phy_config.Mod_id = 0;
  phy_config.CC_id=0;
  phy_config.cfg = req;

  phy_config_request(&phy_config);


  phy_info->remote_port = req->nfapi_config.p7_vnf_port.value;

  struct sockaddr_in vnf_p7_sockaddr;
  memcpy(&vnf_p7_sockaddr.sin_addr.s_addr, &(req->nfapi_config.p7_vnf_address_ipv4.address[0]), 4);
  phy_info->remote_addr = inet_ntoa(vnf_p7_sockaddr.sin_addr);

  printf("[PNF] %d vnf p7 %s:%d timing %d %d %d\n", phy_info->id, phy_info->remote_addr, phy_info->remote_port, 
      phy_info->timing_window, phy_info->timing_info_mode, phy_info->timing_info_period);

  nfapi_config_response_t nfapi_resp;
  memset(&nfapi_resp, 0, sizeof(nfapi_resp));
  nfapi_resp.header.message_id = NFAPI_CONFIG_RESPONSE;
  nfapi_resp.header.phy_id = phy_info->id;
  nfapi_resp.error_code = 0; // DJP - some value resp->error_code;
  nfapi_pnf_config_resp(config, &nfapi_resp);
  printf("[PNF] Sent NFAPI_CONFIG_RESPONSE phy_id:%d\n", phy_info->id);

  return 0;
}

nfapi_p7_message_header_t* pnf_phy_allocate_p7_vendor_ext(uint16_t message_id, uint16_t* msg_size)
{
  if(message_id == P7_VENDOR_EXT_REQ)
  {
    (*msg_size) = sizeof(vendor_ext_p7_req);
    return (nfapi_p7_message_header_t*)malloc(sizeof(vendor_ext_p7_req));
  }

  return 0;
}

void pnf_phy_deallocate_p7_vendor_ext(nfapi_p7_message_header_t* header)
{
  free(header);
}

int pnf_phy_hi_dci0_req(nfapi_pnf_p7_config_t* pnf_p7, nfapi_hi_dci0_request_t* req)
{
  LOG_D(PHY,"[PNF] hi dci0 request sfn_sf:%d dci:%d hi:%d\n", NFAPI_SFNSF2DEC(req->sfn_sf), req->hi_dci0_request_body.number_of_dci, req->hi_dci0_request_body.number_of_hi);
  //phy_info* phy = (phy_info*)(pnf_p7->user_data);

  struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0];
  eNB_rxtx_proc_t *proc = &eNB->proc.proc_rxtx[0];
  for (int i=0; i<req->hi_dci0_request_body.number_of_dci + req->hi_dci0_request_body.number_of_hi; i++)
    //LOG_D(PHY,"[PNF] HI_DCI0_REQ sfn_sf:%d PDU[%d]\n", NFAPI_SFNSF2DEC(req->sfn_sf), i);
    if (req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE)
      LOG_D(PHY,"[PNF] HI_DCI0_REQ sfn_sf:%d PDU[%d] - NFAPI_HI_DCI0_DCI_PDU_TYPE\n", NFAPI_SFNSF2DEC(req->sfn_sf), i);
      nfapi_hi_dci0_request_pdu_t *hi_dci0_req_pdu = &req->hi_dci0_request_body.hi_dci0_pdu_list[i];

      handle_nfapi_hi_dci0_dci_pdu(eNB,proc,hi_dci0_req_pdu);

      eNB->pdcch_vars[NFAPI_SFNSF2SF(req->sfn_sf)&1].num_dci++;
    else if (req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type == NFAPI_HI_DCI0_HI_PDU_TYPE)
    {
      LOG_D(PHY,"[PNF] HI_DCI0_REQ sfn_sf:%d PDU[%d] - NFAPI_HI_DCI0_HI_PDU_TYPE\n", NFAPI_SFNSF2DEC(req->sfn_sf), i);
      nfapi_hi_dci0_request_pdu_t *hi_dci0_req_pdu = &req->hi_dci0_request_body.hi_dci0_pdu_list[i];
      handle_nfapi_hi_dci0_hi_pdu(eNB, proc, hi_dci0_req_pdu);
    else
    {
      LOG_E(PHY,"[PNF] HI_DCI0_REQ sfn_sf:%d PDU[%d] - unknown pdu type:%d\n", NFAPI_SFNSF2DEC(req->sfn_sf), i, req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type);
    }
int pnf_phy_dl_config_req(nfapi_pnf_p7_config_t* pnf_p7, nfapi_dl_config_request_t* req)
{
  LOG_D(PHY,"[PNF] %s() sfn_sf:%d pdcch:%u dl_cfg[dci:%u pdus:%d pdsch_rnti:%d] pcfich:%u\n", __FUNCTION__,NFAPI_SFNSF2DEC(req->sfn_sf), req->dl_config_request_body.number_pdcch_ofdm_symbols, req->dl_config_request_body.number_dci, req->dl_config_request_body.number_pdu, req->dl_config_request_body.number_pdsch_rnti, req->dl_config_request_body.transmission_power_pcfich);
  if (sync_var != 0)
  { 
    NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() Main system not up - is this a dummy subframe?\n", __FUNCTION__);
    return -4;
  int sf = NFAPI_SFNSF2SF(req->sfn_sf);
  struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0];
  eNB_rxtx_proc_t *proc = &eNB->proc.proc_rxtx[0];
  nfapi_dl_config_request_pdu_t* dl_config_pdu_list = req->dl_config_request_body.dl_config_pdu_list;