Add delay between frame send retries

Introduced a delay between retries to allow the bus to stabilize
and ongoing transactions to complete. The delay increases
exponentially, calculated as 30 ms multiplied by 2 raised to the
power of the number of retries.

Change-Id: Ibbfd202118a69c270cbb4f047ef44f15ebf72bd6
Signed-off-by: Cosmo Chou <cosmo.chou@quantatw.com>
diff --git a/ipmbbridged.cpp b/ipmbbridged.cpp
index a2bcf6b..d33e28c 100644
--- a/ipmbbridged.cpp
+++ b/ipmbbridged.cpp
@@ -284,8 +284,27 @@
                         msgToLog.c_str());
                     return;
                 }
-                currentRetryCnt++;
-                ipmbSendI2cFrame(buffer, currentRetryCnt);
+                scheduleFrameResend(buffer, currentRetryCnt);
+            }
+        });
+}
+
+void IpmbChannel::scheduleFrameResend(
+    std::shared_ptr<std::vector<uint8_t>> buffer, size_t retryCount)
+{
+    // SMBus timeout: 30 ms (spec range 25-35 ms)
+    static constexpr size_t resendDelay = 30;
+
+    // Delay increases exponentially with 30 ms multiplied by 2 raised
+    // to the power of retries, e.g.
+    // 1st retry: 30 ms, 2nd: 60 ms, 3rd: 120 ms ...
+    retryTimer.expires_after(
+        std::chrono::milliseconds(resendDelay * (1 << retryCount)));
+    retryTimer.async_wait(
+        [this, buffer, retryCount](const boost::system::error_code& ec) {
+            if (!ec)
+            {
+                ipmbSendI2cFrame(buffer, retryCount + 1);
             }
         });
 }
@@ -527,7 +546,8 @@
                          uint8_t ipmbBmcTargetAddress,
                          uint8_t ipmbRqTargetAddress, uint8_t channelIdx,
                          std::shared_ptr<IpmbCommandFilter> commandFilter) :
-    i2cTargetDescriptor(io), ipmbBmcTargetAddress(ipmbBmcTargetAddress),
+    i2cTargetDescriptor(io), retryTimer(io),
+    ipmbBmcTargetAddress(ipmbBmcTargetAddress),
     ipmbRqTargetAddress(ipmbRqTargetAddress), channelIdx(channelIdx),
     commandFilter(commandFilter)
 {}
diff --git a/ipmbbridged.hpp b/ipmbbridged.hpp
index b8f708a..6805efc 100644
--- a/ipmbbridged.hpp
+++ b/ipmbbridged.hpp
@@ -300,6 +300,7 @@
 
   private:
     boost::asio::posix::stream_descriptor i2cTargetDescriptor;
+    boost::asio::steady_timer retryTimer;
 
     int ipmbi2cTargetFd;
 
@@ -322,6 +323,9 @@
     void makeRequestInvalid(IpmbRequest& request);
 
     void makeRequestValid(std::shared_ptr<IpmbRequest> request);
+
+    void scheduleFrameResend(std::shared_ptr<std::vector<uint8_t>> buffer,
+                             size_t retryCount);
 };
 
 /**