diff --git a/examples/xApp/c/monitor/xapp_kpm_moni.c b/examples/xApp/c/monitor/xapp_kpm_moni.c
index 8b20b4a9a3dacd3c856de41063b9d4b1ffeef69f..5fa00cc2a32aba9b67901e0a239f8823955b8bb1 100644
--- a/examples/xApp/c/monitor/xapp_kpm_moni.c
+++ b/examples/xApp/c/monitor/xapp_kpm_moni.c
@@ -23,6 +23,7 @@
 #include "../../../../src/util/alg_ds/alg/defer.h"
 #include "../../../../src/util/time_now_us.h"
 #include "../../../../src/util/alg_ds/ds/lock_guard/lock_guard.h"
+#include "../../../../src/util/e.h"
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -31,10 +32,142 @@
 #include <signal.h>
 #include <pthread.h>
 
+static
+uint64_t const period_ms = 1000;
 
 static
 pthread_mutex_t mtx;
 
+static
+void log_gnb_ue_id(ue_id_e2sm_t ue_id)
+{
+  if (ue_id.gnb.gnb_cu_ue_f1ap_lst != NULL) {
+    for (size_t i = 0; i < ue_id.gnb.gnb_cu_ue_f1ap_lst_len; i++) {
+      printf("UE ID type = gNB-CU, gnb_cu_ue_f1ap = %u\n", ue_id.gnb.gnb_cu_ue_f1ap_lst[i]);
+    }
+  } else {
+    printf("UE ID type = gNB, amf_ue_ngap_id = %lu\n", ue_id.gnb.amf_ue_ngap_id);
+  }
+  if (ue_id.gnb.ran_ue_id != NULL) {
+    printf("ran_ue_id = %lx\n", *ue_id.gnb.ran_ue_id); // RAN UE NGAP ID
+  }
+}
+
+static
+void log_du_ue_id(ue_id_e2sm_t ue_id)
+{
+  printf("UE ID type = gNB-DU, gnb_cu_ue_f1ap = %u\n", ue_id.gnb_du.gnb_cu_ue_f1ap);
+  if (ue_id.gnb_du.ran_ue_id != NULL) {
+    printf("ran_ue_id = %lx\n", *ue_id.gnb_du.ran_ue_id); // RAN UE NGAP ID
+  }
+}
+
+static
+void log_cuup_ue_id(ue_id_e2sm_t ue_id)
+{
+  printf("UE ID type = gNB-CU-UP, gnb_cu_cp_ue_e1ap = %u\n", ue_id.gnb_cu_up.gnb_cu_cp_ue_e1ap);
+  if (ue_id.gnb_cu_up.ran_ue_id != NULL) {
+    printf("ran_ue_id = %lx\n", *ue_id.gnb_cu_up.ran_ue_id); // RAN UE NGAP ID
+  }
+}
+
+typedef void (*log_ue_id)(ue_id_e2sm_t ue_id);
+
+static
+log_ue_id log_ue_id_e2sm[END_UE_ID_E2SM] = {
+    log_gnb_ue_id, // common for gNB-mono, CU and CU-CP
+    log_du_ue_id,
+    log_cuup_ue_id,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+};
+
+static
+void log_int_value(byte_array_t name, meas_record_lst_t meas_record)
+{
+  if (cmp_str_ba("RRU.PrbTotDl", name) == 0) {
+    printf("RRU.PrbTotDl = %d [PRBs]\n", meas_record.int_val);
+  } else if (cmp_str_ba("RRU.PrbTotUl", name) == 0) {
+    printf("RRU.PrbTotUl = %d [PRBs]\n", meas_record.int_val);
+  } else if (cmp_str_ba("DRB.PdcpSduVolumeDL", name) == 0) {
+    printf("DRB.PdcpSduVolumeDL = %d [kb]\n", meas_record.int_val);
+  } else if (cmp_str_ba("DRB.PdcpSduVolumeUL", name) == 0) {
+    printf("DRB.PdcpSduVolumeUL = %d [kb]\n", meas_record.int_val);
+  } else {
+    printf("Measurement Name not yet supported\n");
+  }
+}
+
+static
+void log_real_value(byte_array_t name, meas_record_lst_t meas_record)
+{
+  if (cmp_str_ba("DRB.RlcSduDelayDl", name) == 0) {
+    printf("DRB.RlcSduDelayDl = %.2f [μs]\n", meas_record.real_val);
+  } else if (cmp_str_ba("DRB.UEThpDl", name) == 0) {
+    printf("DRB.UEThpDl = %.2f [kbps]\n", meas_record.real_val);
+  } else if (cmp_str_ba("DRB.UEThpUl", name) == 0) {
+    printf("DRB.UEThpUl = %.2f [kbps]\n", meas_record.real_val);
+  } else {
+    printf("Measurement Name not yet supported\n");
+  }
+}
+
+typedef void (*log_meas_value)(byte_array_t name, meas_record_lst_t meas_record);
+
+static
+log_meas_value get_meas_value[END_MEAS_VALUE] = {
+    log_int_value,
+    log_real_value,
+    NULL,
+};
+
+static
+void match_meas_name_type(meas_type_t meas_type, meas_record_lst_t meas_record)
+{
+  // Get the value of the Measurement
+  get_meas_value[meas_record.value](meas_type.name, meas_record);
+}
+
+static
+void match_id_meas_type(meas_type_t meas_type, meas_record_lst_t meas_record)
+{
+  (void)meas_type;
+  (void)meas_record;
+  assert(false && "ID Measurement Type not yet supported");
+}
+
+typedef void (*check_meas_type)(meas_type_t meas_type, meas_record_lst_t meas_record);
+
+static
+check_meas_type match_meas_type[END_MEAS_TYPE] = {
+    match_meas_name_type,
+    match_id_meas_type,
+};
+
+static
+void log_kpm_measurements(kpm_ind_msg_format_1_t const* msg_frm_1)
+{
+  assert(msg_frm_1->meas_info_lst_len > 0 && "Cannot correctly print measurements");
+
+  // UE Measurements per granularity period
+  for (size_t j = 0; j < msg_frm_1->meas_data_lst_len; j++) {
+    meas_data_lst_t const data_item = msg_frm_1->meas_data_lst[j];
+
+    for (size_t z = 0; z < data_item.meas_record_len; z++) {
+      meas_type_t const meas_type = msg_frm_1->meas_info_lst[z].meas_type;
+      meas_record_lst_t const record_item = data_item.meas_record_lst[z];
+
+      match_meas_type[meas_type.type](meas_type, record_item);
+
+      if (data_item.incomplete_flag && *data_item.incomplete_flag == TRUE_ENUM_VALUE)
+        printf("Measurement Record not reliable");
+    }
+  }
+
+}
+
 static
 void sm_cb_kpm(sm_ag_if_rd_t const* rd)
 {
@@ -46,277 +179,201 @@ void sm_cb_kpm(sm_ag_if_rd_t const* rd)
   kpm_ind_data_t const* ind = &rd->ind.kpm.ind;
   kpm_ric_ind_hdr_format_1_t const* hdr_frm_1 = &ind->hdr.kpm_ric_ind_hdr_format_1;
   kpm_ind_msg_format_3_t const* msg_frm_3 = &ind->msg.frm_3;
-  
 
   int64_t const now = time_now_us();
   static int counter = 1;
   {
     lock_guard(&mtx);
 
-    printf("\n%7d KPM ind_msg latency = %ld [μs]\n", counter, now - hdr_frm_1->collectStartTime);  // xApp <-> E2 Node
+    printf("\n%7d KPM ind_msg latency = %ld [μs]\n", counter, now - hdr_frm_1->collectStartTime); // xApp <-> E2 Node
 
     // Reported list of measurements per UE
-    for (size_t i = 0; i < msg_frm_3->ue_meas_report_lst_len; i++)
-    {
-      switch (msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst.type)
-      {
-      case GNB_UE_ID_E2SM:
-        if (msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst.gnb.gnb_cu_ue_f1ap_lst != NULL)
-        {
-          for (size_t j = 0; j < msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst.gnb.gnb_cu_ue_f1ap_lst_len; j++)
-          {
-            printf("UE ID type = gNB-CU, gnb_cu_ue_f1ap = %u\n", msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst.gnb.gnb_cu_ue_f1ap_lst[j]);
-          }
-        }
-        else
-        {
-          printf("UE ID type = gNB, amf_ue_ngap_id = %lu\n", msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst.gnb.amf_ue_ngap_id);
-        }
-        break;
-
-      case GNB_DU_UE_ID_E2SM:
-        printf("UE ID type = gNB-DU, gnb_cu_ue_f1ap = %u\n", msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst.gnb_du.gnb_cu_ue_f1ap);
-        break;
-
-      case GNB_CU_UP_UE_ID_E2SM:
-        printf("UE ID type = gNB-CU-UP, gnb_cu_cp_ue_e1ap = %u\n", msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst.gnb_cu_up.gnb_cu_cp_ue_e1ap);
-        break;
+    for (size_t i = 0; i < msg_frm_3->ue_meas_report_lst_len; i++) {
+      // log UE ID
+      ue_id_e2sm_t const ue_id_e2sm = msg_frm_3->meas_report_per_ue[i].ue_meas_report_lst;
+      ue_id_e2sm_e const type = ue_id_e2sm.type;
+      log_ue_id_e2sm[type](ue_id_e2sm);
+
+      // log measurements
+      log_kpm_measurements(&msg_frm_3->meas_report_per_ue[i].ind_msg_format_1);
       
-      default:
-        assert(false && "UE ID type not yet implemented");
-      }
-
-      kpm_ind_msg_format_1_t const* msg_frm_1 = &msg_frm_3->meas_report_per_ue[i].ind_msg_format_1;
-
-      // UE Measurements per granularity period
-      for (size_t j = 0; j<msg_frm_1->meas_data_lst_len; j++)
-      {
-        for (size_t z = 0; z<msg_frm_1->meas_data_lst[j].meas_record_len; z++)
-        {
-          if (msg_frm_1->meas_info_lst_len > 0)
-          {
-            switch (msg_frm_1->meas_info_lst[z].meas_type.type)
-            {
-            case NAME_MEAS_TYPE:
-            {
-              // Get the Measurement Name
-              char meas_info_name_str[msg_frm_1->meas_info_lst[z].meas_type.name.len + 1];
-              memcpy(meas_info_name_str, msg_frm_1->meas_info_lst[z].meas_type.name.buf, msg_frm_1->meas_info_lst[z].meas_type.name.len);
-              meas_info_name_str[msg_frm_1->meas_info_lst[z].meas_type.name.len] = '\0';
-
-              // Get the value of the Measurement
-              switch (msg_frm_1->meas_data_lst[j].meas_record_lst[z].value)
-              {
-              case REAL_MEAS_VALUE:
-              {
-                if (strcmp(meas_info_name_str, "DRB.RlcSduDelayDl") == 0)
-                {
-                  printf("DRB.RlcSduDelayDl = %.2f [μs]\n", msg_frm_1->meas_data_lst[j].meas_record_lst[z].real_val);
-                }
-                else if (strcmp(meas_info_name_str, "DRB.UEThpDl") == 0)
-                {
-                  printf("DRB.UEThpDl = %.2f [kbps]\n", msg_frm_1->meas_data_lst[j].meas_record_lst[z].real_val);
-                }
-                else if (strcmp(meas_info_name_str, "DRB.UEThpUl") == 0)
-                {
-                  printf("DRB.UEThpUl = %.2f [kbps]\n", msg_frm_1->meas_data_lst[j].meas_record_lst[z].real_val);
-                }
-                else
-                {
-                  printf("Measurement Name not yet implemented %s\n", meas_info_name_str);
-                  //assert(false && "Measurement Name not yet implemented");
-                }
-
-                break;
-              }
-                
-
-              case INTEGER_MEAS_VALUE:
-              {
-                if (strcmp(meas_info_name_str, "RRU.PrbTotDl") == 0)
-                {
-                  printf("RRU.PrbTotDl = %d [PRBs]\n", msg_frm_1->meas_data_lst[j].meas_record_lst[z].int_val);
-                }
-                else if (strcmp(meas_info_name_str, "RRU.PrbTotUl") == 0)
-                {
-                  printf("RRU.PrbTotUl = %d [PRBs]\n", msg_frm_1->meas_data_lst[j].meas_record_lst[z].int_val);
-                }
-                else if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeDL") == 0)
-                {
-                  printf("DRB.PdcpSduVolumeDL = %d [kb]\n", msg_frm_1->meas_data_lst[j].meas_record_lst[z].int_val);
-                }
-                else if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeUL") == 0)
-                {
-                  printf("DRB.PdcpSduVolumeUL = %d [kb]\n", msg_frm_1->meas_data_lst[j].meas_record_lst[z].int_val);
-                }
-                else
-                {
-                  printf("Measurement Name not yet implemented %s\n", meas_info_name_str);
-                  //assert(false && "Measurement Name not yet implemented");
-                }
-
-                break;
-              }
-              
-              default:
-                assert(0 != 0 && "Value not recognized");
-              }
-              
-              break;
-            }
-            case ID_MEAS_TYPE: 
-                printf(" ID_MEAS_TYPE \n");
-                break;
-          
-            default:
-              assert(false && "Measurement Type not yet implemented");
-            }
-          }
-          
-
-          if (msg_frm_1->meas_data_lst[j].incomplete_flag && *msg_frm_1->meas_data_lst[j].incomplete_flag == TRUE_ENUM_VALUE)
-            printf("Measurement Record not reliable");
-        }        
-      }
     }
     counter++;
   }
 }
 
 static
-kpm_event_trigger_def_t gen_ev_trig(uint64_t period)
+test_info_lst_t filter_predicate(test_cond_type_e type, test_cond_e cond, int value)
 {
-  kpm_event_trigger_def_t dst = {0};
+  test_info_lst_t dst = {0};
+
+  dst.test_cond_type = type;
+  // It can only be TRUE_TEST_COND_TYPE so it does not matter the type
+  // but ugly ugly...
+  dst.S_NSSAI = TRUE_TEST_COND_TYPE;
 
-  dst.type = FORMAT_1_RIC_EVENT_TRIGGER;
-  dst.kpm_ric_event_trigger_format_1.report_period_ms = period;
+  dst.test_cond = calloc(1, sizeof(test_cond_e));
+  assert(dst.test_cond != NULL && "Memory exhausted");
+  *dst.test_cond = cond;
+
+  dst.test_cond_value = calloc(1, sizeof(test_cond_value_t));
+  assert(dst.test_cond_value != NULL && "Memory exhausted");
+  dst.test_cond_value->type = OCTET_STRING_TEST_COND_VALUE;
+
+  dst.test_cond_value->octet_string_value = calloc(1, sizeof(byte_array_t));
+  assert(dst.test_cond_value->octet_string_value != NULL && "Memory exhausted");
+  const size_t len_nssai = 1;
+  dst.test_cond_value->octet_string_value->len = len_nssai;
+  dst.test_cond_value->octet_string_value->buf = calloc(len_nssai, sizeof(uint8_t));
+  assert(dst.test_cond_value->octet_string_value->buf != NULL && "Memory exhausted");
+  dst.test_cond_value->octet_string_value->buf[0] = value;
 
   return dst;
 }
 
 static
-meas_info_format_1_lst_t gen_meas_info_format_1_lst(const char* action)
+label_info_lst_t fill_kpm_label(void)
 {
-  meas_info_format_1_lst_t dst = {0};
-
-  dst.meas_type.type = NAME_MEAS_TYPE;
-  // ETSI TS 128 552
-  dst.meas_type.name = cp_str_to_ba(action);
+  label_info_lst_t label_item = {0};
 
-  dst.label_info_lst_len = 1;
-  dst.label_info_lst = calloc(1, sizeof(label_info_lst_t));
-  assert(dst.label_info_lst != NULL && "Memory exhausted");
-  dst.label_info_lst[0].noLabel = calloc(1, sizeof(enum_value_e));
-  assert(dst.label_info_lst[0].noLabel != NULL && "Memory exhausted");
-  *dst.label_info_lst[0].noLabel = TRUE_ENUM_VALUE;
+  label_item.noLabel = ecalloc(1, sizeof(enum_value_e));
+  *label_item.noLabel = TRUE_ENUM_VALUE;
 
-  return dst;
+  return label_item;
 }
 
 static
-kpm_act_def_format_1_t gen_act_def_frmt_1(char** action)
+kpm_act_def_format_1_t fill_act_def_frm_1(ric_report_style_item_t const* report_item)
 {
-  kpm_act_def_format_1_t dst = {0};
+  assert(report_item != NULL);
+
+  kpm_act_def_format_1_t ad_frm_1 = {0};
 
-  dst.gran_period_ms = 1000;
+  size_t const sz = report_item->meas_info_for_action_lst_len;
 
   // [1, 65535]
-  size_t count = 0;
-  while (action[count] != NULL) {
-    count++;
+  ad_frm_1.meas_info_lst_len = sz;
+  ad_frm_1.meas_info_lst = calloc(sz, sizeof(meas_info_format_1_lst_t));
+  assert(ad_frm_1.meas_info_lst != NULL && "Memory exhausted");
+
+  for (size_t i = 0; i < sz; i++) {
+    meas_info_format_1_lst_t* meas_item = &ad_frm_1.meas_info_lst[i];
+    // 8.3.9
+    // Measurement Name
+    meas_item->meas_type.type = NAME_MEAS_TYPE;
+    meas_item->meas_type.name = copy_byte_array(report_item->meas_info_for_action_lst[i].name);
+
+    // [1, 2147483647]
+    // 8.3.11
+    meas_item->label_info_lst_len = 1;
+    meas_item->label_info_lst = ecalloc(1, sizeof(label_info_lst_t));
+    meas_item->label_info_lst[0] = fill_kpm_label();
   }
-  dst.meas_info_lst_len = count;
-  dst.meas_info_lst = calloc(count, sizeof(meas_info_format_1_lst_t));
-  assert(dst.meas_info_lst != NULL && "Memory exhausted");
 
-  for(size_t i = 0; i < dst.meas_info_lst_len; i++) {
-    dst.meas_info_lst[i] = gen_meas_info_format_1_lst(action[i]);
-  }
+  // 8.3.8 [0, 4294967295]
+  ad_frm_1.gran_period_ms = period_ms;
 
-  return dst;
+  // 8.3.20 - OPTIONAL
+  ad_frm_1.cell_global_id = NULL;
+
+#if defined KPM_V2_03 || defined KPM_V3_00
+  // [0, 65535]
+  ad_frm_1.meas_bin_range_info_lst_len = 0;
+  ad_frm_1.meas_bin_info_lst = NULL;
+#endif
+
+  return ad_frm_1;
 }
 
 static
-test_info_lst_t filter_predicate(test_cond_type_e type, test_cond_e cond, int value)
+kpm_act_def_t fill_report_style_4(ric_report_style_item_t const* report_item)
 {
-  test_info_lst_t dst = {0};
+  assert(report_item != NULL);
+  assert(report_item->act_def_format_type == FORMAT_4_ACTION_DEFINITION);
 
-  dst.test_cond_type = type;
-  // It can only be TRUE_TEST_COND_TYPE so it does not matter the type
-  dst.S_NSSAI = TRUE_TEST_COND_TYPE;
+  kpm_act_def_t act_def = {.type = FORMAT_4_ACTION_DEFINITION};
 
-  dst.test_cond = calloc(1, sizeof(test_cond_e));
-  assert(dst.test_cond != NULL && "Memory exhausted");
-  *dst.test_cond = cond;
+  // Fill matching condition
+  // [1, 32768]
+  act_def.frm_4.matching_cond_lst_len = 1;
+  act_def.frm_4.matching_cond_lst = calloc(act_def.frm_4.matching_cond_lst_len, sizeof(matching_condition_format_4_lst_t));
+  assert(act_def.frm_4.matching_cond_lst != NULL && "Memory exhausted");
+  // Filter connected UEs by S-NSSAI criteria
+  test_cond_type_e const type = S_NSSAI_TEST_COND_TYPE; // CQI_TEST_COND_TYPE
+  test_cond_e const condition = EQUAL_TEST_COND; // GREATERTHAN_TEST_COND
+  int const value = 1;
+  act_def.frm_4.matching_cond_lst[0].test_info_lst = filter_predicate(type, condition, value);
 
-  dst.test_cond_value = calloc(1, sizeof(test_cond_value_t));
-  assert(dst.test_cond_value != NULL && "Memory exhausted");
-  dst.test_cond_value->type = INTEGER_TEST_COND_VALUE;
+  // Fill Action Definition Format 1
+  // 8.2.1.2.1
+  act_def.frm_4.action_def_format_1 = fill_act_def_frm_1(report_item);
 
-  dst.test_cond_value->int_value = calloc(1, sizeof(int64_t));
-  assert(dst.test_cond_value->int_value != NULL && "Memory exhausted");
-  *dst.test_cond_value->int_value = value;
+  return act_def;
+}
 
-  return dst;
-} 
+typedef kpm_act_def_t (*fill_kpm_act_def)(ric_report_style_item_t const* report_item);
 
+static
+fill_kpm_act_def get_kpm_act_def[END_RIC_SERVICE_REPORT] = {
+    NULL,
+    NULL,
+    NULL,
+    fill_report_style_4,
+    NULL,
+};
 
 static
-kpm_act_def_format_4_t gen_act_def_frmt_4(char** action)
+kpm_sub_data_t gen_kpm_subs(kpm_ran_function_def_t const* ran_func)
 {
-  kpm_act_def_format_4_t dst = {0};
+  assert(ran_func != NULL);
+  assert(ran_func->ric_event_trigger_style_list != NULL);
 
-  // [1, 32768]
-  dst.matching_cond_lst_len = 1;
+  kpm_sub_data_t kpm_sub = {0};
 
-  dst.matching_cond_lst = calloc(dst.matching_cond_lst_len, sizeof(matching_condition_format_4_lst_t));
-  assert(dst.matching_cond_lst != NULL && "Memory exhausted");
+  // Generate Event Trigger
+  assert(ran_func->ric_event_trigger_style_list[0].format_type == FORMAT_1_RIC_EVENT_TRIGGER);
+  kpm_sub.ev_trg_def.type = FORMAT_1_RIC_EVENT_TRIGGER;
+  kpm_sub.ev_trg_def.kpm_ric_event_trigger_format_1.report_period_ms = period_ms;
 
-  // Filter connected UEs by S-NSSAI criteria
-  test_cond_type_e const type = S_NSSAI_TEST_COND_TYPE;
-  test_cond_e const condition = EQUAL_TEST_COND;
-  int const value = 1;
-  dst.matching_cond_lst[0].test_info_lst = filter_predicate(type, condition, value);
+  // Generate Action Definition
+  kpm_sub.sz_ad = 1;
+  kpm_sub.ad = calloc(kpm_sub.sz_ad, sizeof(kpm_act_def_t));
+  assert(kpm_sub.ad != NULL && "Memory exhausted");
 
-  printf("[xApp]: Filter UEs by S-NSSAI criteria where SST = %lu\n", *dst.matching_cond_lst[0].test_info_lst.test_cond_value->int_value);
+  // Multiple Action Definitions in one SUBSCRIPTION message is not supported in this project
+  // Multiple REPORT Styles = Multiple Action Definition = Multiple SUBSCRIPTION messages
+  ric_report_style_item_t* const report_item = &ran_func->ric_report_style_list[0];
+  ric_service_report_e const report_style_type = report_item->report_style_type;
+  *kpm_sub.ad = get_kpm_act_def[report_style_type](report_item);
 
-  // Action definition Format 1
-  dst.action_def_format_1 = gen_act_def_frmt_1(action);  // 8.2.1.2.1
-
-  return dst;
+  return kpm_sub;
 }
 
 static
-kpm_act_def_t gen_act_def(char** act)
+bool eq_sm(sm_ran_function_t const* elem, int const id)
 {
-  kpm_act_def_t dst = {0};
+  if (elem->id == id)
+    return true;
 
-  dst.type = FORMAT_4_ACTION_DEFINITION;
-  dst.frm_4 = gen_act_def_frmt_4(act);
-  return dst;
+  return false;
 }
 
 static
-char** lst_kpm_measurement(kpm_ran_function_def_t const* src)
+size_t find_sm_idx(sm_ran_function_t* rf, size_t sz, bool (*f)(sm_ran_function_t const*, int const), int const id)
 {
-  assert(src != NULL);
-  const size_t sz = src->ric_report_style_list[0].meas_info_for_action_lst_len;
-  char** dst = calloc(sz + 1, sizeof(char*));
-  for(size_t i = 0; i < sz; ++i){
-    const size_t len = src->ric_report_style_list[0].meas_info_for_action_lst[i].name.len;
-    const uint8_t* buf = src->ric_report_style_list[0].meas_info_for_action_lst[i].name.buf;
-    dst[i] = calloc(len+1, sizeof(uint8_t));
-    memcpy(dst[i], buf, len);
+  for (size_t i = 0; i < sz; i++) {
+    if (f(&rf[i], id))
+      return i;
   }
-  return dst;
-}
 
+  assert(0 != 0 && "SM ID could not be found in the RAN Function List");
+}
 
-int main(int argc, char *argv[])
+int main(int argc, char* argv[])
 {
   fr_args_t args = init_fr_args(argc, argv);
 
-  //Init the xApp
+  // Init the xApp
   init_xapp_api(&args);
   sleep(1);
 
@@ -331,103 +388,47 @@ int main(int argc, char *argv[])
   int rc = pthread_mutex_init(&mtx, &attr);
   assert(rc == 0);
 
-  // KPM indication
-  sm_ans_xapp_t* kpm_handle = NULL;
-  if(nodes.len > 0){
-    kpm_handle = calloc( nodes.len, sizeof(sm_ans_xapp_t) ); 
-    assert(kpm_handle != NULL);
-  }
+  sm_ans_xapp_t* hndl = calloc(nodes.len, sizeof(sm_ans_xapp_t));
+  assert(hndl != NULL);
 
-  const int KPM_ran_function = 2;
+  ////////////
+  // START KPM
+  ////////////
+  int const KPM_ran_function = 2;
 
-  for (int i = 0; i < nodes.len; i++) {
+  for (size_t i = 0; i < nodes.len; ++i) {
     e2_node_connected_xapp_t* n = &nodes.n[i];
-    char** lst = NULL; 
-    for (size_t j = 0; j < n->len_rf; j++){
-      printf("[xApp]: registered node %lu ran func id = %d \n ", j, n->rf[j].id);
-      if(n->rf[j].id == KPM_ran_function){
-        lst = lst_kpm_measurement(&n->rf[j].defn.kpm);
-      }   
-    }
-
-    ////////////
-    // START KPM
-    ////////////
-    kpm_sub_data_t kpm_sub = {0};
-    defer({ free_kpm_sub_data(&kpm_sub); });
-
-    // KPM Event Trigger
-    uint64_t period_ms = 1000;
-    kpm_sub.ev_trg_def = gen_ev_trig(period_ms);
-    printf("[xApp]: reporting period = %lu [ms]\n", period_ms);
-
-    // KPM Action Definition
-    kpm_sub.sz_ad = 1;
-    kpm_sub.ad = calloc(1, sizeof(kpm_act_def_t));
-    assert(kpm_sub.ad != NULL && "Memory exhausted");
-
-    *kpm_sub.ad = gen_act_def(lst);
-
-
-
-    switch (n->id.type)
-    {
-    case ngran_gNB: ;
-      char *act_gnb[] = {"DRB.PdcpSduVolumeDL", "DRB.PdcpSduVolumeUL", "DRB.RlcSduDelayDl", "DRB.UEThpDl", "DRB.UEThpUl", "RRU.PrbTotDl", "RRU.PrbTotUl", NULL}; // 3GPP TS 28.552
-      *kpm_sub.ad = gen_act_def(act_gnb);
-      break;
-    case ngran_eNB: ;
-      char *act_enb[] = {"DRB.PdcpSduVolumeDL", "DRB.PdcpSduVolumeUL", "RRU.PrbTotDl", "RRU.PrbTotUl", NULL}; // 3GPP TS 32.425
-      *kpm_sub.ad = gen_act_def(act_enb);
-      break;
-
-    case ngran_gNB_CUUP: ;
-    case ngran_gNB_CU: ;
-      char *act_gnb_cu[] = {"DRB.PdcpSduVolumeDL", "DRB.PdcpSduVolumeUL", NULL}; // 3GPP TS 28.552
-      *kpm_sub.ad = gen_act_def(act_gnb_cu);
-      break;
-
-    case ngran_gNB_DU: ;
-      char *act_gnb_du[] = {"DRB.RlcSduDelayDl", "DRB.UEThpDl", "DRB.UEThpUl", "RRU.PrbTotDl", "RRU.PrbTotUl", NULL}; // 3GPP TS 28.552
-      *kpm_sub.ad = gen_act_def(act_gnb_du);
-      break;
-
-    case ngran_gNB_CUCP: ;
-      continue;
-    
-    default:
-      assert(false && "NG-RAN Type not yet implemented");
-    }
 
+    size_t const idx = find_sm_idx(n->rf, n->len_rf, eq_sm, KPM_ran_function);
+    assert(n->rf[idx].defn.type == KPM_RAN_FUNC_DEF_E && "KPM is not the received RAN Function");
+    // if REPORT Service is supported by E2 node, send SUBSCRIPTION
+    // e.g. OAI CU-CP
+    if (n->rf[idx].defn.kpm.ric_report_style_list != NULL) {
+      // Generate KPM SUBSCRIPTION message
+      kpm_sub_data_t kpm_sub = gen_kpm_subs(&n->rf[idx].defn.kpm);
 
-    
-    kpm_handle[i] = report_sm_xapp_api(&nodes.n[i].id, KPM_ran_function, &kpm_sub, sm_cb_kpm);
-    assert(kpm_handle[i].success == true);
+      hndl[i] = report_sm_xapp_api(&n->id, KPM_ran_function, &kpm_sub, sm_cb_kpm);
+      assert(hndl[i].success == true);
 
-    if(lst != NULL){
-      for(size_t i = 0; lst[i] != NULL; ++i){
-        free(lst[i]);
-      }
-      free(lst);
+      free_kpm_sub_data(&kpm_sub);
     }
   }
+  ////////////
+  // END KPM
+  ////////////
 
   sleep(10);
 
-  for(int i = 0; i < nodes.len; ++i){
+  for (int i = 0; i < nodes.len; ++i) {
     // Remove the handle previously returned
-    if (kpm_handle[i].success == true)
-      rm_report_sm_xapp_api(kpm_handle[i].u.handle);
+    if (hndl[i].success == true)
+      rm_report_sm_xapp_api(hndl[i].u.handle);
   }
+  free(hndl);
 
-  if(nodes.len > 0){
-    free(kpm_handle);
-  }
-
-  //Stop the xApp
-  while(try_stop_xapp_api() == false)
+  // Stop the xApp
+  while (try_stop_xapp_api() == false)
     usleep(1000);
 
   printf("Test xApp run SUCCESSFULLY\n");
 }
-