[VOL-2152][BAL3.0 Brigade] OpenOLT driver registers ONU Remote Defect
Indicator alarm
- Provide missing BAL API definitions required for unit test compilation

Change-Id: Ifb38a55b24413beb9f5caf864403c4513cd7be68
diff --git a/agent/src/core_api_handler.cc b/agent/src/core_api_handler.cc
index 6319faa..54f7e0d 100644
--- a/agent/src/core_api_handler.cc
+++ b/agent/src/core_api_handler.cc
@@ -90,6 +90,117 @@
     return s_actions_ptr;
 }
 
+bcmolt_stat_alarm_config set_stat_alarm_config(const openolt::OnuItuPonAlarm* request) {
+    bcmolt_stat_alarm_config alarm_cfg = {};
+    bcmolt_stat_alarm_trigger_config trigger_obj = {};
+    bcmolt_stat_alarm_soak_config soak_obj = {};
+
+    switch (request->alarm_reporting_condition()) {
+        case openolt::OnuItuPonAlarm::RATE_THRESHOLD:
+            trigger_obj.type = BCMOLT_STAT_CONDITION_TYPE_RATE_THRESHOLD;
+            BCMOLT_FIELD_SET(&trigger_obj.u.rate_threshold, stat_alarm_trigger_config_rate_threshold,
+                    rising, request->rate_threshold_config().rate_threshold_rising());
+            BCMOLT_FIELD_SET(&trigger_obj.u.rate_threshold, stat_alarm_trigger_config_rate_threshold,
+                    falling, request->rate_threshold_config().rate_threshold_falling());
+            BCMOLT_FIELD_SET(&soak_obj, stat_alarm_soak_config, active_soak_time,
+                    request->rate_threshold_config().soak_time().active_soak_time());
+            BCMOLT_FIELD_SET(&soak_obj, stat_alarm_soak_config, clear_soak_time,
+                    request->rate_threshold_config().soak_time().clear_soak_time());
+            break;
+        case openolt::OnuItuPonAlarm::RATE_RANGE:
+            trigger_obj.type = BCMOLT_STAT_CONDITION_TYPE_RATE_RANGE;
+            BCMOLT_FIELD_SET(&trigger_obj.u.rate_range, stat_alarm_trigger_config_rate_range, upper,
+                    request->rate_range_config().rate_range_upper());
+            BCMOLT_FIELD_SET(&trigger_obj.u.rate_range, stat_alarm_trigger_config_rate_range, lower,
+                    request->rate_range_config().rate_range_lower());
+            BCMOLT_FIELD_SET(&soak_obj, stat_alarm_soak_config, active_soak_time,
+                    request->rate_range_config().soak_time().active_soak_time());
+            BCMOLT_FIELD_SET(&soak_obj, stat_alarm_soak_config, clear_soak_time,
+                    request->rate_range_config().soak_time().clear_soak_time());
+            break;
+        case openolt::OnuItuPonAlarm::VALUE_THRESHOLD:
+            trigger_obj.type = BCMOLT_STAT_CONDITION_TYPE_VALUE_THRESHOLD;
+            BCMOLT_FIELD_SET(&trigger_obj.u.value_threshold, stat_alarm_trigger_config_value_threshold,
+                    limit, request->value_threshold_config().threshold_limit());
+            BCMOLT_FIELD_SET(&soak_obj, stat_alarm_soak_config, active_soak_time,
+                    request->value_threshold_config().soak_time().active_soak_time());
+            BCMOLT_FIELD_SET(&soak_obj, stat_alarm_soak_config, clear_soak_time,
+                    request->value_threshold_config().soak_time().clear_soak_time());
+            break;
+        default:
+            OPENOLT_LOG(ERROR, openolt_log_id, "unsupported alarm reporting condition = %u\n", request->alarm_reporting_condition());
+            // For now just log the error and not return error. We can handle this scenario in the future.
+            break;
+    }
+
+    BCMOLT_FIELD_SET(&alarm_cfg, stat_alarm_config, trigger, trigger_obj);
+    BCMOLT_FIELD_SET(&alarm_cfg, stat_alarm_config, soak, soak_obj);
+
+    return alarm_cfg;
+}
+
+Status OnuItuPonAlarmSet_(const openolt::OnuItuPonAlarm* request) {
+    bcmos_errno err;
+    bcmolt_onu_itu_pon_stats_cfg stat_cfg; /* declare main API struct */
+    bcmolt_onu_key key = {}; /* declare key */
+    bcmolt_stat_alarm_config errors_cfg = {};
+
+    key.pon_ni = request->pon_ni();
+    key.onu_id = request->onu_id();
+
+    /* Initialize the API struct. */
+    BCMOLT_STAT_CFG_INIT(&stat_cfg, onu, itu_pon_stats, key);
+
+    /*
+       1. BCMOLT_STAT_CONDITION_TYPE_NONE = 0, The alarm is disabled.
+       2. BCMOLT_STAT_CONDITION_TYPE_RATE_THRESHOLD = 1, The alarm is triggered if the stats delta value between samples
+                                                   crosses the configured threshold boundary.
+           rising: The alarm is raised if the stats delta value per second becomes greater than this threshold level.
+           falling: The alarm is cleared if the stats delta value per second becomes less than this threshold level.
+       3. BCMOLT_STAT_CONDITION_TYPE_RATE_RANGE = 2, The alarm is triggered if the stats delta value between samples
+                                               deviates from the configured range.
+           upper: The alarm is raised if the stats delta value per second becomes greater than this upper level.
+           lower: The alarm is raised if the stats delta value per second becomes less than this lower level.
+       4. BCMOLT_STAT_CONDITION_TYPE_VALUE_THRESHOLD = 3, The alarm is raised if the stats sample value becomes greater
+                                                    than this level.  The alarm is cleared when the host read the stats.
+           limit: The alarm is raised if the stats sample value becomes greater than this level.
+                  The alarm is cleared when the host clears the stats.
+
+       active_soak_time: If the alarm condition is raised and stays in the raised state for at least this amount
+                         of time (unit=seconds), the alarm indication is sent to the host.
+                         The OLT delays the alarm indication no less than this delay period.
+                         It can be delayed more than this period because of the statistics sampling interval.
+       clear_soak_time: After the alarm is raised, if it is cleared and stays in the cleared state for at least
+                        this amount of time (unit=seconds), the alarm indication is sent to the host.
+                        The OLT delays the alarm indication no less than this delay period. It can be delayed more
+                        than this period because of the statistics sampling interval.
+    */
+
+    errors_cfg = set_stat_alarm_config(request);
+
+    switch (request->alarm_id()) {
+        case openolt::OnuItuPonAlarm_AlarmID::OnuItuPonAlarm_AlarmID_RDI_ERRORS:
+            //set the rdi_errors alarm
+            BCMOLT_FIELD_SET(&stat_cfg.data, onu_itu_pon_stats_cfg_data, rdi_errors, errors_cfg);
+            break;
+        default:
+            OPENOLT_LOG(ERROR, openolt_log_id, "could not find the alarm id %d\n", request->alarm_id());
+            return bcm_to_grpc_err(BCM_ERR_PARM, "the alarm id is wrong");
+    }
+
+    err = bcmolt_stat_cfg_set(dev_id, &stat_cfg.hdr);
+    if (err != BCM_ERR_OK) {
+        OPENOLT_LOG(ERROR, openolt_log_id, "Failed to set onu itu pon stats, alarm id %d, pon_ni %d, onu_id %d, err = %s\n",
+                request->alarm_id(), key.pon_ni, key.onu_id, bcmos_strerror(err));
+        return bcm_to_grpc_err(err, "set Onu ITU PON stats alarm faild");
+    } else {
+        OPENOLT_LOG(INFO, openolt_log_id, "set onu itu pon stats alarm %d successfully, pon_ni %d, onu_id %d\n",
+                request->alarm_id(), key.pon_ni, key.onu_id);
+    }
+
+    return Status::OK;
+}
+
 Status GetDeviceInfo_(openolt::DeviceInfo* device_info) {
     device_info->set_vendor(VENDOR_ID);
     device_info->set_model(MODEL_ID);
diff --git a/agent/src/indications.cc b/agent/src/indications.cc
index 7c1c90d..759f419 100644
--- a/agent/src/indications.cc
+++ b/agent/src/indications.cc
@@ -38,7 +38,6 @@
 extern std::map<alloc_cfg_compltd_key,  Queue<alloc_cfg_complete_result> *> alloc_cfg_compltd_map;
 extern bcmos_fastlock alloc_cfg_wait_lock;
 
-
 bool subscribed = false;
 uint32_t nni_intf_id = 0;
 #define current_device 0
@@ -93,6 +92,43 @@
     return "unknown";
 }
 
+inline uint64_t get_pon_stats_alarms_data(bcmolt_interface pon_ni, bcmolt_onu_id onu_id, bcmolt_onu_itu_pon_stats_data_id stat) {
+    bcmos_errno err;
+    bcmolt_onu_itu_pon_stats itu_pon_stat; /* declare main API struct */
+    bcmolt_onu_key key = {}; /* declare key */
+    bcmolt_stat_flags clear_on_read = BCMOLT_STAT_FLAGS_NONE; /* declare 'clear on read' flag */
+
+    key.pon_ni = pon_ni;
+    key.onu_id = onu_id;
+
+    /* Initialize the API struct. */
+    BCMOLT_STAT_INIT(&itu_pon_stat, onu, itu_pon_stats, key);
+    switch (stat) {
+        case BCMOLT_ONU_ITU_PON_STATS_DATA_ID_RDI_ERRORS:
+            BCMOLT_FIELD_SET_PRESENT(&itu_pon_stat.data, onu_itu_pon_stats_data, rdi_errors);
+            err = bcmolt_stat_get(dev_id, &itu_pon_stat.hdr, clear_on_read ? BCMOLT_STAT_FLAGS_CLEAR_ON_READ : BCMOLT_STAT_FLAGS_NONE);
+            if (err) {
+                OPENOLT_LOG(ERROR, openolt_log_id, "Failed to get rdi_errors, err = %s\n", bcmos_strerror(err));
+                return err;
+            }
+            return itu_pon_stat.data.rdi_errors;
+        /* It is a further requirement
+        case BCMOLT_ONU_ITU_PON_STATS_DATA_ID_BIP_ERRORS:
+            BCMOLT_FIELD_SET_PRESENT(&itu_pon_stat.data, onu_itu_pon_stats_data, bip_errors);
+            err = bcmolt_stat_get(dev_id, &itu_pon_stat.hdr, clear_on_read ? BCMOLT_STAT_FLAGS_CLEAR_ON_READ : BCMOLT_STAT_FLAGS_NONE);
+            if (err) {
+                OPENOLT_LOG(ERROR, openolt_log_id, "Failed to get bip_errors, err = %s\n", bcmos_strerror(err));
+                return err;
+            }
+            return itu_pon_stat.data.bip_errors;
+        */
+        default:
+            return BCM_ERR_INTERNAL;
+    }
+
+    return err;
+}
+
 /*std::string getOnuRegistrationId(uint32_t intf_id, uint32_t onu_id){
     bcmbal_subscriber_terminal_key key;
     bcmbal_subscriber_terminal_cfg sub_term_obj = {};
@@ -828,7 +864,7 @@
     bcmolt_msg_free(msg);
 }
 
-static void OnuItuPonStatsIndication(bcmolt_devid olt, bcmolt_msg *msg) {
+static void OnuItuPonStatsAlarmRaisedIndication(bcmolt_devid olt, bcmolt_msg *msg) {
     openolt::Indication ind;
     openolt::AlarmIndication* alarm_ind = new openolt::AlarmIndication;
     openolt::OnuItuPonStatsIndication* onu_itu_pon_stats_ind = new openolt::OnuItuPonStatsIndication;
@@ -836,20 +872,41 @@
     switch (msg->obj_type) {
         case BCMOLT_OBJ_ID_ONU:
             switch (msg->subgroup) {
-                case BCMOLT_ONU_STAT_SUBGROUP_ITU_PON_STATS:
+                case BCMOLT_ONU_AUTO_SUBGROUP_ITU_PON_STATS_ALARM_RAISED:
                 {
-                    bcmolt_onu_key *key = &((bcmolt_onu_itu_pon_stats*)msg)->key;
-                    bcmolt_onu_itu_pon_stats_data *data = &((bcmolt_onu_itu_pon_stats*)msg)->data;
+                    bcmolt_onu_key *onu_key = &((bcmolt_onu_itu_pon_stats_alarm_raised*)msg)->key;
+                    bcmolt_onu_itu_pon_stats_alarm_raised_data *data = &((bcmolt_onu_itu_pon_stats_alarm_raised*)msg)->data;
 
-                    OPENOLT_LOG(INFO, openolt_log_id, "Got onu rdi erros, intf_id %d, onu_id %d, rdi_errors %"PRIu64"\n",
-                        key->pon_ni, key->onu_id, data->rdi_errors);
-
-                    onu_itu_pon_stats_ind->set_intf_id(key->pon_ni);
-                    onu_itu_pon_stats_ind->set_onu_id(key->onu_id);
-                    onu_itu_pon_stats_ind->set_rdi_errors(data->rdi_errors);
-                    alarm_ind->set_allocated_onu_itu_pon_stats_ind(onu_itu_pon_stats_ind);
-
-                    ind.set_allocated_alarm_ind(alarm_ind);
+                    if (_BCMOLT_FIELD_MASK_BIT_IS_SET(data->presence_mask, BCMOLT_ONU_ITU_PON_STATS_ALARM_RAISED_DATA_ID_STAT)) {
+                        switch (data->stat)
+                        {
+                            case BCMOLT_ONU_ITU_PON_STATS_DATA_ID_RDI_ERRORS:
+                                uint64_t rdi_errors;
+                                openolt::RdiErrorIndication* rdi_err_ind = new openolt::RdiErrorIndication;
+                                rdi_errors = get_pon_stats_alarms_data(onu_key->pon_ni, onu_key->onu_id, data->stat);
+                                onu_itu_pon_stats_ind->set_intf_id(onu_key->pon_ni);
+                                onu_itu_pon_stats_ind->set_onu_id(onu_key->onu_id);
+                                rdi_err_ind->set_rdi_error_count(rdi_errors);
+                                rdi_err_ind->set_status("on");
+                                onu_itu_pon_stats_ind->set_allocated_rdi_error_ind(rdi_err_ind);
+                                OPENOLT_LOG(INFO, openolt_log_id, "Got onu raised alarm indication, intf_id %d, onu_id %d, \
+                                        rdi_errors %"PRIu64"\n", onu_key->pon_ni, onu_key->onu_id, rdi_errors);
+                                alarm_ind->set_allocated_onu_itu_pon_stats_ind(onu_itu_pon_stats_ind);
+                                break;
+                            /* It is a further requirement
+                            case BCMOLT_ONU_ITU_PON_STATS_DATA_ID_BIP_ERRORS:
+                                uint64_t bip_errors;
+                                bip_errors = get_pon_stats_alarms_data(onu_key->pon_ni, onu_key->onu_id, data->stat);
+                                onu_itu_pon_stats_ind->set_intf_id(onu_key->pon_ni);
+                                onu_itu_pon_stats_ind->set_onu_id(onu_key->onu_id);
+                                OPENOLT_LOG(INFO, openolt_log_id, "Got onu raised alarm indication, intf_id %d, onu_id %d, \
+                                        bip_errors %"PRIu64"\n", onu_key->pon_ni, onu_key->onu_id, bip_errors);
+                                alarm_ind->set_allocated_onu_itu_pon_stats_ind(onu_itu_pon_stats_ind);
+                                break;
+                            */
+                        }
+                        ind.set_allocated_alarm_ind(alarm_ind);
+                    }
                 }
             }
     }
@@ -858,7 +915,58 @@
     bcmolt_msg_free(msg);
 }
 
+static void OnuItuPonStatsAlarmClearedIndication(bcmolt_devid olt, bcmolt_msg *msg) {
+    openolt::Indication ind;
+    openolt::AlarmIndication* alarm_ind = new openolt::AlarmIndication;
+    openolt::OnuItuPonStatsIndication* onu_itu_pon_stats_ind = new openolt::OnuItuPonStatsIndication;
 
+    switch (msg->obj_type) {
+        case BCMOLT_OBJ_ID_ONU:
+            switch (msg->subgroup) {
+                case BCMOLT_ONU_AUTO_SUBGROUP_ITU_PON_STATS_ALARM_CLEARED:
+                {
+                    bcmolt_onu_key *onu_key = &((bcmolt_onu_itu_pon_stats_alarm_cleared*)msg)->key;
+                    bcmolt_onu_itu_pon_stats_alarm_cleared_data *data = &((bcmolt_onu_itu_pon_stats_alarm_cleared*)msg)->data;
+
+                    if (_BCMOLT_FIELD_MASK_BIT_IS_SET(data->presence_mask, BCMOLT_ONU_ITU_PON_STATS_ALARM_CLEARED_DATA_ID_STAT)) {
+                        switch (data->stat)
+                        {
+                            case BCMOLT_ONU_ITU_PON_STATS_DATA_ID_RDI_ERRORS:
+                                uint64_t rdi_errors;
+                                openolt::RdiErrorIndication* rdi_err_ind = new openolt::RdiErrorIndication;
+
+                                rdi_errors = get_pon_stats_alarms_data(onu_key->pon_ni, onu_key->onu_id, data->stat);
+                                onu_itu_pon_stats_ind->set_intf_id(onu_key->pon_ni);
+                                onu_itu_pon_stats_ind->set_onu_id(onu_key->onu_id);
+                                rdi_err_ind->set_rdi_error_count(rdi_errors);
+                                rdi_err_ind->set_status("off");
+                                onu_itu_pon_stats_ind->set_allocated_rdi_error_ind(rdi_err_ind);
+                                OPENOLT_LOG(INFO, openolt_log_id, "Got onu cleared alarm indication, intf_id %d, onu_id %d, \
+                                        rdi_errors %"PRIu64"\n", onu_key->pon_ni, onu_key->onu_id, rdi_errors);
+                                alarm_ind->set_allocated_onu_itu_pon_stats_ind(onu_itu_pon_stats_ind);
+                                break;
+                            /* It is a further requirement
+                            case BCMOLT_ONU_ITU_PON_STATS_DATA_ID_BIP_ERRORS:
+                                uint64_t bip_errors;
+                                bip_errors = get_pon_stats_alarms_data(onu_key->pon_ni, onu_key->onu_id, data->stat);
+                                onu_itu_pon_stats_ind->set_intf_id(onu_key->pon_ni);
+                                onu_itu_pon_stats_ind->set_onu_id(onu_key->onu_id);
+                                onu_itu_pon_stats_ind->set_bip_errors(bip_errors);
+                                OPENOLT_LOG(INFO, openolt_log_id, "Got onu cleared alarm indication, intf_id %d, onu_id %d, \
+                                        bip_errors %"PRIu64"\n", onu_key->pon_ni, onu_key->onu_id, bip_errors);
+                                alarm_ind->set_allocated_onu_itu_pon_stats_ind(onu_itu_pon_stats_ind);
+                                break;
+                            */
+                        }
+                        ind.set_allocated_alarm_ind(alarm_ind);
+                    }
+                }
+            }
+    }
+
+    oltIndQ.push(ind);
+    bcmolt_msg_free(msg);
+}
 
 static void OnuDeactivationCompletedIndication(bcmolt_devid olt, bcmolt_msg *msg) {
     openolt::Indication ind;
@@ -930,7 +1038,6 @@
     OPENOLT_LOG(WARNING, openolt_log_id, "onu processing error indication, intf_id %d, onu_id %d\n",
         key->intf_id, key->sub_term_id);
 
-
     onu_proc_error_ind->set_intf_id(key->intf_id);
     onu_proc_error_ind->set_onu_id(key->sub_term_id);
 
@@ -1139,14 +1246,23 @@
     if(rc != BCM_ERR_OK)
         return Status(grpc::StatusCode::INTERNAL, "onu loss of key sync indication subscribe failed");
 
-    /* ONU ITU-PON Stats Indiction */
+    /* ONU ITU-PON Raised Stats Indiction */
     rx_cfg.obj_type = BCMOLT_OBJ_ID_ONU;
-    rx_cfg.rx_cb = OnuItuPonStatsIndication;
+    rx_cfg.rx_cb = OnuItuPonStatsAlarmRaisedIndication;
     rx_cfg.flags = BCMOLT_AUTO_FLAGS_NONE;
-    rx_cfg.subgroup = bcmolt_onu_stat_subgroup_itu_pon_stats;
+    rx_cfg.subgroup = bcmolt_onu_auto_subgroup_itu_pon_stats_alarm_raised;
     rc = bcmolt_ind_subscribe(current_device, &rx_cfg);
     if(rc != BCM_ERR_OK)
-        return Status(grpc::StatusCode::INTERNAL, "onu itu-pon stats indication subscribe failed");
+        return Status(grpc::StatusCode::INTERNAL, "onu itu-pon raised stats indication subscribe failed");
+
+    /* ONU ITU-PON Cleared Stats Indiction */
+    rx_cfg.obj_type = BCMOLT_OBJ_ID_ONU;
+    rx_cfg.rx_cb = OnuItuPonStatsAlarmClearedIndication;
+    rx_cfg.flags = BCMOLT_AUTO_FLAGS_NONE;
+    rx_cfg.subgroup = bcmolt_onu_auto_subgroup_itu_pon_stats_alarm_cleared;
+    rc = bcmolt_ind_subscribe(current_device, &rx_cfg);
+    if(rc != BCM_ERR_OK)
+        return Status(grpc::StatusCode::INTERNAL, "onu itu-pon cleared stats indication subscribe failed");
 
     /* Packet-In by Access_Control */
     rx_cfg.obj_type = BCMOLT_OBJ_ID_ACCESS_CONTROL;
diff --git a/agent/src/stats_collection.cc b/agent/src/stats_collection.cc
index 9caa98e..4979366 100644
--- a/agent/src/stats_collection.cc
+++ b/agent/src/stats_collection.cc
@@ -34,7 +34,7 @@
 #define FLOWS_COUNT 100
 
 bcmolt_flow_key* flows_keys = new bcmolt_flow_key[FLOWS_COUNT];
-bcmolt_odid device_id = 0;    
+bcmolt_odid device_id = 0;
 
 void init_stats() {
     memset(flows_keys, 0, FLOWS_COUNT * sizeof(bcmolt_flow_key));
@@ -84,7 +84,6 @@
     bcmolt_onu_itu_pon_stats pon_stats;
     bcmolt_pon_interface_itu_pon_stats itu_pon_stats;
 
-
     switch (intf_ref.intf_type) {
         case BCMOLT_INTERFACE_TYPE_NNI:
         {
@@ -111,7 +110,7 @@
             {
                 //std::cout << "Interface statistics retrieved"
                 //          << " intf_id:" << intf_id << std::endl;
-            
+
                 port_stats->set_rx_bytes(nni_stats.data.rx_bytes);
                 port_stats->set_rx_packets(nni_stats.data.rx_packets);
                 port_stats->set_rx_ucast_packets(nni_stats.data.rx_ucast_packets);
@@ -124,7 +123,7 @@
                 port_stats->set_tx_mcast_packets(nni_stats.data.tx_mcast_packets);
                 port_stats->set_tx_bcast_packets(nni_stats.data.tx_bcast_packets);
                 port_stats->set_tx_error_packets(nni_stats.data.tx_error_packets);
-            
+
             } else {
                 OPENOLT_LOG(ERROR, openolt_log_id,  "Failed to retrieve port statistics, intf_id %d, intf_type %d, err = %s\n",
                     (int)intf_ref.intf_id, (int)intf_ref.intf_type, bcmos_strerror(err));
@@ -171,7 +170,7 @@
             }
             break;
         }
-    } 
+    }
 
     port_stats->set_intf_id(interface_key_to_port_no((bcmolt_interface_id)intf_ref.intf_id, (bcmolt_interface_type)intf_ref.intf_type));
     time_t now;
@@ -222,7 +221,6 @@
 }
 #endif
 
-
 void stats_collection() {
 
     if (!state.is_connected()) {
@@ -234,7 +232,6 @@
         return;
     }
 
-
     OPENOLT_LOG(DEBUG, openolt_log_id, "Collecting statistics\n");
 
     //Ports statistics
@@ -258,7 +255,7 @@
         intf_ref.intf_type = BCMOLT_INTERFACE_TYPE_PON;
         intf_ref.intf_id = i;
 
-        openolt::PortStatistics* port_stats = 
+        openolt::PortStatistics* port_stats =
             collectPortStatistics(intf_ref);
 
         openolt::Indication ind;