[VOL-4069] Measure and read Rx optical power for an ONU

Reading Rx optical power requires triggering an RSSI measurement and tracking the RSSI Measurement Completed indication.
The raw value is converted to mW, and a dBm value is returned back.
A small test application (~40K) is bundled within the Debian package to help with debugging the optical power levels.

Change-Id: I20f304a9de0c47b94dfd7b1d8fdd52c56d6a2983
diff --git a/agent/common/Queue.h b/agent/common/Queue.h
index 2e366ce..8e90a75 100644
--- a/agent/common/Queue.h
+++ b/agent/common/Queue.h
@@ -17,6 +17,44 @@
 class Queue
 {
  public:
+  /**
+   * @brief      pop with timeout
+   * @details    This pop() checks the queue within the given timeout duration at each given interval.
+   *             Use of the out parameter is for exception safety reasons.
+   *             The timeout duration is decreased at each check interval, so that it may be <= 0.
+   * <a href="https://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html">Implementing a Thread-Safe Queue using Condition Variables (Updated)</a>
+   * @param[out] value              pop queue.front()
+   * @param[in]  timeout_duration   time out after this duration
+   * @param[in]  check_interval     check at each this interval
+   * @return     [true] if pop happens within the timeout duration, [false] otherwise
+   */
+  bool pop(T& value,
+    std::chrono::milliseconds timeout_duration,
+    const std::chrono::milliseconds& check_interval=std::chrono::milliseconds(10)) {
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    while (queue_.empty()) {
+      if (cond_.wait_for(lock, check_interval) == std::cv_status::timeout) {
+        timeout_duration -= check_interval;
+        if (timeout_duration <= std::chrono::milliseconds::zero() ) {
+          return false;
+        }
+      }
+    }
+
+    value = queue_.front();
+    queue_.pop();
+    return true;
+  }
+
+  /**
+   * @brief      returns the number of elements
+   * @return     Returns the number of elements in the underlying container.
+   */
+  std::size_t size() {
+    std::unique_lock<std::mutex> lock(mutex_);
+    return queue_.size();
+  }
 
   // timeout is in milliseconds, wait_granularity in milliseconds
   std::pair<T, bool> pop(int timeout, int wait_granularity=10)
@@ -66,7 +104,7 @@
   Queue()=default;
   Queue(const Queue&) = delete;            // disable copying
   Queue& operator=(const Queue&) = delete; // disable assignment
-  
+
  private:
   std::queue<T> queue_;
   std::mutex mutex_;
diff --git a/agent/common/core.h b/agent/common/core.h
index b3a5408..09ff890 100644
--- a/agent/common/core.h
+++ b/agent/common/core.h
@@ -243,6 +243,7 @@
 Status GetLogicalOnuDistance_(uint32_t intf_id, uint32_t onu_id, openolt::OnuLogicalDistance* response);
 Status GetOnuStatistics_(uint32_t intf_id, uint32_t onu_id, openolt::OnuStatistics *onu_stats);
 Status GetGemPortStatistics_(uint32_t intf_id, uint32_t gemport_id, openolt::GemPortStatistics* gemport_stats);
+Status GetPonRxPower_(uint32_t intf_id, uint32_t onu_id, openolt::PonRxPowerData* response);
 int get_status_bcm_cli_quit(void);
 uint16_t get_dev_id(void);
 Status pushOltOperInd(uint32_t intf_id, const char *type, const char *state);
diff --git a/agent/common/server.cc b/agent/common/server.cc
index 68cce10..168df68 100644
--- a/agent/common/server.cc
+++ b/agent/common/server.cc
@@ -347,6 +347,16 @@
             request->gemport_id(),
             response);
     }
+
+    Status GetPonRxPower(
+            ServerContext* context,
+            const openolt::Onu* request,
+            openolt::PonRxPowerData* response) override {
+        return GetPonRxPower_(
+            request->intf_id(),
+            request->onu_id(),
+            response);
+    }
 };
 
 bool RunServer(int argc, char** argv) {