ipmbsensor: Add delay to init cmd

Sometimes we run the init cmd too early and we start
getting sensor readings that are out of range. Normally
this is only 1-2 sensors. Add in a delay so that hopefully
this won't happen. Also don't print errors too often.

Tested-by: Power cycled multiple times and never saw NA
for sensor readings.

Change-Id: Ib1d336fc5b04b2c96e41b5de2a89d26c7a6d3e83
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/src/IpmbSensor.cpp b/src/IpmbSensor.cpp
index e72f1af..2870d33 100644
--- a/src/IpmbSensor.cpp
+++ b/src/IpmbSensor.cpp
@@ -47,6 +47,8 @@
 
 boost::container::flat_map<std::string, std::unique_ptr<IpmbSensor>> sensors;
 
+std::unique_ptr<boost::asio::deadline_timer> initCmdTimer;
+
 IpmbSensor::IpmbSensor(std::shared_ptr<sdbusplus::asio::connection>& conn,
                        boost::asio::io_service& io,
                        const std::string& sensorName,
@@ -114,7 +116,6 @@
                         << "Error setting init command for device: " << name
                         << "\n";
                 }
-                read();
             },
             "xyz.openbmc_project.Ipmi.Channel.Ipmb",
             "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
@@ -200,9 +201,15 @@
             [this](boost::system::error_code ec,
                    const IpmbMethodType& response) {
                 const int& status = std::get<0>(response);
+                static bool firstError = true; // don't print too much
                 if (ec || status)
                 {
-                    std::cerr << "Error reading from device: " << name << "\n";
+                    if (firstError)
+                    {
+                        std::cerr << "Error reading from device: " << name
+                                  << "\n";
+                        firstError = false;
+                    }
                     updateValue(0);
                     read();
                     return;
@@ -228,8 +235,12 @@
                 {
                     if (data.empty())
                     {
-                        std::cerr << "Invalid data from device: " << name
-                                  << "\n";
+                        if (firstError)
+                        {
+                            std::cerr << "Invalid data from device: " << name
+                                      << "\n";
+                            firstError = false;
+                        }
                         read();
                         return;
                     }
@@ -240,8 +251,12 @@
                 {
                     if (data.size() < 4)
                     {
-                        std::cerr << "Invalid data from device: " << name
-                                  << "\n";
+                        if (firstError)
+                        {
+                            std::cerr << "Invalid data from device: " << name
+                                      << "\n";
+                            firstError = false;
+                        }
                         read();
                         return;
                     }
@@ -252,8 +267,12 @@
                 {
                     if (data.size() < 4)
                     {
-                        std::cerr << "Invalid data from device: " << name
-                                  << "\n";
+                        if (firstError)
+                        {
+                            std::cerr << "Invalid data from device: " << name
+                                      << "\n";
+                            firstError = false;
+                        }
                         read();
                         return;
                     }
@@ -265,6 +284,7 @@
                 }
                 updateValue(value);
                 read();
+                firstError = true; // success
             },
             "xyz.openbmc_project.Ipmi.Channel.Ipmb",
             "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
@@ -358,23 +378,41 @@
 
 void reinitSensors(sdbusplus::message::message& message)
 {
-
+    constexpr const size_t reinitWaitSeconds = 2;
     std::string objectName;
     boost::container::flat_map<std::string, std::variant<int32_t>> values;
     message.read(objectName, values);
+
     auto findPgood = values.find("pgood");
     if (findPgood != values.end())
     {
         int32_t powerStatus = std::get<int32_t>(findPgood->second);
         if (powerStatus)
         {
-            for (auto& sensor : sensors)
+            if (!initCmdTimer)
             {
-                if (sensor.second)
-                {
-                    sensor.second->runInitCmd();
-                }
+                // this should be impossible
+                return;
             }
+            // we seem to send this command too fast sometimes, wait before
+            // sending
+            initCmdTimer->expires_from_now(
+                boost::posix_time::seconds(reinitWaitSeconds));
+
+            initCmdTimer->async_wait([](const boost::system::error_code ec) {
+                if (ec == boost::asio::error::operation_aborted)
+                {
+                    return; // we're being canceled
+                }
+
+                for (const auto& sensor : sensors)
+                {
+                    if (sensor.second)
+                    {
+                        sensor.second->runInitCmd();
+                    }
+                }
+            });
         }
     }
 }
@@ -387,6 +425,8 @@
     systemBus->request_name("xyz.openbmc_project.IpmbSensor");
     sdbusplus::asio::object_server objectServer(systemBus);
 
+    initCmdTimer = std::make_unique<boost::asio::deadline_timer>(io);
+
     io.post([&]() { createSensors(io, objectServer, sensors, systemBus); });
 
     boost::asio::deadline_timer configTimer(io);