From c619f6eff76234d2efd14d29e99d8132dd768946 Mon Sep 17 00:00:00 2001
From: Robert Schmidt <robert.schmidt@eurecom.fr>
Date: Tue, 12 Dec 2017 10:03:06 +0100
Subject: [PATCH] Feature: Provide restart for lte-softmodem

- {restart,stop}_L1L2() in lte-softmodem.c
- add function start_phy_rrc() in enb_app.{c,h}, accessible from outside
- will be used to restart PHY and RRC when lte-softmodem is restarted

use only one FlexRAN wait function
---
 openair2/ENB_APP/enb_app.c                    |  30 ++--
 openair2/ENB_APP/enb_app.h                    |   7 +
 .../ENB_APP/flexran_agent_common_internal.c   |  28 +++-
 targets/RT/USER/lte-softmodem.c               | 129 +++++++++++++++++-
 targets/RT/USER/lte-softmodem.h               |   3 +
 5 files changed, 176 insertions(+), 21 deletions(-)

diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c
index 89e20889cb..be0b88acff 100644
--- a/openair2/ENB_APP/enb_app.c
+++ b/openair2/ENB_APP/enb_app.c
@@ -57,14 +57,13 @@ extern unsigned char NB_eNB_INST;
 #endif
 extern volatile int     node_control_state;
 
-static void enb_app_wait_reconfig_cmd (void)
+void ltesm_wait_reconfig_cmd(void)
 {
-  LOG_I(ENB_APP, "ENB APP await reconfiguration command\n");
-   
-  while (node_control_state == ENB_WAIT_RECONFIGURATION_CMD) {
+  LOG_I(ENB_APP, "LTE Softmodem wait reconfiguration command\n");
+
+  while (node_control_state ==  ENB_WAIT_RECONFIGURATION_CMD) {
     usleep(200000);
   }
-  sleep(2); // wait for createing other tasks
 }
 
 #if defined(ENABLE_ITTI)
@@ -202,6 +201,15 @@ static void configure_rrc(uint32_t enb_id, const Enb_properties_array_t *enb_pro
   itti_send_msg_to_task (TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
 }
 
+void enb_app_start_phy_rrc(uint32_t enb_id_start, uint32_t enb_id_end)
+{
+  Enb_properties_array_t *enb_properties_p = enb_config_get();
+  for (uint32_t enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) {
+    configure_phy(enb_id, enb_properties_p);
+    configure_rrc(enb_id, enb_properties_p);
+  }
+}
+
 /*------------------------------------------------------------------------------*/
 # if defined(ENABLE_USE_MME)
 static uint32_t eNB_app_register(uint32_t enb_id_start, uint32_t enb_id_end, const Enb_properties_array_t *enb_properties)
@@ -325,8 +333,10 @@ void *eNB_app_task(void *args_p)
   for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) {
     flexran_agent_start(enb_id, enb_properties_p);
   }
-  // wait for config comd from the controller/network app
-  enb_app_wait_reconfig_cmd();
+  // wait for config comd from the controller/network app plus some time so
+  // that the other Tasks are in place
+  ltesm_wait_reconfig_cmd();
+  sleep(2);
   
   // set again the ran api vars  
   for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) {
@@ -336,11 +346,7 @@ void *eNB_app_task(void *args_p)
 
 #endif 
 
-  for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) {
-    configure_phy(enb_id, enb_properties_p);
-    configure_rrc(enb_id, enb_properties_p);
-  }
-
+  enb_app_start_phy_rrc(enb_id_start, enb_id_end);
   
 # if defined(ENABLE_USE_MME)
   /* Try to register each eNB */
diff --git a/openair2/ENB_APP/enb_app.h b/openair2/ENB_APP/enb_app.h
index 8e3c28760b..be5adfbb34 100644
--- a/openair2/ENB_APP/enb_app.h
+++ b/openair2/ENB_APP/enb_app.h
@@ -30,8 +30,15 @@
 #ifndef ENB_APP_H_
 #define ENB_APP_H_
 
+#include <stdint.h>
 
 
 void *eNB_app_task(void *args_p);
 
+/* needed for flexran: start PHY and RRC when restarting */
+void enb_app_start_phy_rrc(uint32_t enb_id_start, uint32_t enb_id_end);
+
+/* wait that FlexRAN left state ENB_WAIT_RECONFIGURATION_CMD */
+void ltesm_wait_reconfig_cmd(void);
+
 #endif /* ENB_APP_H_ */
diff --git a/openair2/ENB_APP/flexran_agent_common_internal.c b/openair2/ENB_APP/flexran_agent_common_internal.c
index e2ee656b23..e77557e9ee 100644
--- a/openair2/ENB_APP/flexran_agent_common_internal.c
+++ b/openair2/ENB_APP/flexran_agent_common_internal.c
@@ -31,8 +31,33 @@
 
 #include "flexran_agent_common_internal.h"
 #include "flexran_agent_mac_internal.h"
+
+/* the following is needed to soft-restart the lte-softmodem */
+#include "targets/RT/USER/lte-softmodem.h"
+#include "assertions.h"
+#include "enb_app.h"
 extern volatile int    node_control_state;
 
+void handle_reconfiguration(mid_t mod_id)
+{
+  /* NOTE: this function might be extended by using stop_modem()
+   * to halt the modem so that it can later be resumed */
+
+  if (ENB_NORMAL_OPERATION != node_control_state) {
+    node_control_state = ENB_NORMAL_OPERATION;
+  } else {
+    if (stop_L1L2(mod_id) < 0 || restart_L1L2(mod_id) < 0) {
+      LOG_E(ENB_APP, "could not restart, killing lte-softmodem\n");
+      /* shutdown the whole lte-softmodem */
+      itti_terminate_tasks(TASK_PHY_ENB);
+      return;
+    }
+
+    enb_app_start_phy_rrc(mod_id, mod_id+1);
+    LOG_I(ENB_APP, "lte-softmodem restart succeeded\n");
+  }
+}
+
 int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy_length) {
 
   yaml_parser_t parser;
@@ -72,8 +97,7 @@ int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy
 	if (parse_enb_id(mod_id, &parser) == -1) {
 	  goto error;
 	} else { // succeful parse and setting 
-	  node_control_state= ENB_NORMAL_OPERATION;
-	  LOG_I(ENB_APP, "Successful parsed config for enb system, entering normal state\n");
+          handle_reconfiguration(mod_id);
 	}
       } else if (strcmp((char *) event.data.scalar.value, "mac") == 0) {
 	LOG_D(ENB_APP, "This is intended for the mac system\n");
diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c
index d36907bba7..b89c82aff4 100644
--- a/targets/RT/USER/lte-softmodem.c
+++ b/targets/RT/USER/lte-softmodem.c
@@ -1487,18 +1487,128 @@ void fill_PHY_vars_eNB_g(uint8_t abstraction_flag, uint8_t beta_ACK, uint8_t bet
   }
 }
 
-/* check the state : either continue or wait for a command to start/stop the eNB
- * if needed override the current configuration parameters, such as 
- * frequencies, bands, power, bandwidth
+#if defined(ENABLE_ITTI) && defined(FLEXRAN_AGENT_SB_IF)
+/*
+ * helper function to terminate a certain ITTI task
  */
-static void ltesm_wait_reconfig_cmd(void)
+void terminate_task(task_id_t task_id, mid_t mod_id)
 {
-  LOG_I(ENB_APP, "LTE Softmodem wait reconfiguration command\n");
+  LOG_I(ENB_APP, "sending TERMINATE_MESSAGE to task %s (%d)\n", itti_get_task_name(task_id), task_id);
+  MessageDef *msg;
+  msg = itti_alloc_new_message (ENB_APP, TERMINATE_MESSAGE);
+  itti_send_msg_to_task (task_id, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg);
+}
+
+int stop_L1L2(int enb_id)
+{
+  int CC_id;
+
+  LOG_W(ENB_APP, "stopping lte-softmodem\n");
+
+  /* stop trx devices */
+  for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+    if (PHY_vars_eNB_g[0][CC_id]->rfdevice.trx_stop_func) {
+        LOG_I(ENB_APP, "stopping PHY_vars_eNB_g[0][%d]->rfdevice (via trx_stop_func())\n", CC_id);
+        PHY_vars_eNB_g[0][CC_id]->rfdevice.trx_stop_func(&PHY_vars_eNB_g[0][CC_id]->rfdevice);
+    }
+    if (PHY_vars_eNB_g[0][CC_id]->ifdevice.trx_stop_func) {
+        LOG_I(ENB_APP, "stopping PHY_vars_eNB_g[0][%d]->ifdevice (via trx_stop_func())\n", CC_id);
+        PHY_vars_eNB_g[0][CC_id]->ifdevice.trx_stop_func(&PHY_vars_eNB_g[0][CC_id]->ifdevice);
+    }
+  }
+
+  /* these tasks need to pick up new configuration */
+  terminate_task(TASK_RRC_ENB, enb_id);
+  terminate_task(TASK_L2L1, enb_id);
+  oai_exit = 1;
+  LOG_W(ENB_APP, "calling kill_eNB_proc() for instance %d\n", enb_id);
+  kill_eNB_proc(enb_id);
+  /* give some time for all threads */
+  sleep(1);
+  return 0;
+}
+
+/*
+ * Restart the lte-softmodem.
+ * This function checks whether we are in ENB_NORMAL_OPERATION (defined by
+ * FlexRAN). If yes, first stop L1/L2/L3, then resume.
+ */
+int restart_L1L2(int enb_id)
+{
+  int i, aa, CC_id;
+  /* needed for fill_PHY_vars_eNB_g(), defined locally in main();
+   * abstraction flag is needed too, but defined both globally and in main () */
+  uint8_t beta_ACK = 0, beta_RI = 0, beta_CQI = 2;
+  /* needed for macphy_init() */
+  int eMBMS_active = 0;
+
+  LOG_W(ENB_APP, "restarting lte-softmodem\n");
+
+  /* block threads */
+  sync_var = -1;
+  oai_exit = 0;
+
+  reconfigure_enb_params(enb_id);     /* set frame parameters from configuration */
+
+  /* PHY_vars_eNB_g will be filled by init_lte_eNB(), so free and
+   * let the data structure be filled again */
+  for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+    free(PHY_vars_eNB_g[0][CC_id]);
+    fill_PHY_vars_eNB_g(abstraction_flag, beta_ACK, beta_RI, beta_CQI);
+  }
+
+  dump_frame_parms(frame_parms[0]);
+  init_openair0();
+
+  /* give MAC interface current cell information, the rest is the same.
+   * For more info, check l2_init(). Then, initialize it (cf. line 1904). */
+  mac_xface->frame_parms = frame_parms[0];
+  mac_xface->macphy_init(eMBMS_active,(uecap_xer_in==1)?uecap_xer:NULL,0,0);
+
+  LOG_I(ENB_APP, "attempting to create ITTI tasks\n");
+  if (itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL) < 0) {
+    LOG_E(RRC, "Create task for RRC eNB failed\n");
+    return -1;
+  } else {
+    LOG_I(RRC, "Re-created task for RRC eNB successfully\n");
+  }
+  if (itti_create_task (TASK_L2L1, l2l1_task, NULL) < 0) {
+    LOG_E(PDCP, "Create task for L2L1 failed\n");
+    return -1;
+  } else {
+    LOG_I(PDCP, "Re-created task for L2L1 successfully\n");
+  }
+
+  /* TODO XForms here */
 
-  while (node_control_state ==  ENB_WAIT_RECONFIGURATION_CMD) {
-    usleep(200000);
+  printf("Initializing eNB threads\n");
+  init_eNB(node_function, node_timing, 1, eth_params, single_thread_flag, wait_for_sync);
+  for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+      PHY_vars_eNB_g[0][CC_id]->rf_map.card=0;
+      PHY_vars_eNB_g[0][CC_id]->rf_map.chain=CC_id+chain_offset;
   }
+
+  mlockall(MCL_CURRENT | MCL_FUTURE);
+
+  printf("Setting eNB buffer to all-RX\n");
+  // Set LSBs for antenna switch (ExpressMIMO)
+  for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+    PHY_vars_eNB_g[0][CC_id]->hw_timing_advance = 0;
+    for (i=0; i<frame_parms[CC_id]->samples_per_tti*10; i++)
+      for (aa=0; aa<frame_parms[CC_id]->nb_antennas_tx; aa++)
+        PHY_vars_eNB_g[0][CC_id]->common_vars.txdata[0][aa][i] = 0x00010001;
+  }
+
+  printf("Sending sync to all threads\n");
+
+  pthread_mutex_lock(&sync_mutex);
+  sync_var=0;
+  pthread_cond_broadcast(&sync_cond);
+  pthread_mutex_unlock(&sync_mutex);
+
+  return 0;
 }
+#endif
 
 int main( int argc, char **argv ) {
     int i,aa;
@@ -1689,7 +1799,12 @@ int main( int argc, char **argv ) {
     }
 
     create_enb_app_task(UE_flag ? 0 : 1);
+
+#ifdef FLEXRAN_AGENT_SB_IF
+    /* wait command for flexran agent: only start when configuration received */
     ltesm_wait_reconfig_cmd ();
+#endif
+
     // reconfigure_enb: 0 for wait, 1 for skip, and other values to reconfigure
     for (i=0; (i < NB_eNB_INST && node_control_state == ENB_NORMAL_OPERATION ) ; i++){
       reconfigure_enb_params(i);
diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h
index 4d9d145c68..a0883c3d59 100644
--- a/targets/RT/USER/lte-softmodem.h
+++ b/targets/RT/USER/lte-softmodem.h
@@ -89,4 +89,7 @@ extern void init_fep_thread(PHY_VARS_eNB *, pthread_attr_t *);
 extern void init_td_thread(PHY_VARS_eNB *, pthread_attr_t *);
 extern void init_te_thread(PHY_VARS_eNB *, pthread_attr_t *);
 
+extern int stop_L1L2(int enb_id);
+extern int restart_L1L2(int enb_id);
+
 #endif
-- 
2.26.2