pid/zone: Restore PWM when fans returned to auto

This makes use of the improved write() interface, to allow the
PID-loop-determined PWM to be restored, when the fan is returned to
automatic mode.

Without this fix, a fan set to manual mode, then manually set to a
different speed, would not properly return to the correct speed, when
transitioning back to automatic from manual.

This patch also adds a stub to allow the caller to learn the raw PWM
value written as output, another useful write() interface improvement.
Although not the topic of this change, it is included here, to avoid
later patch conflicts.

Tested: I can now correctly toggle between automatic, and manual, fan
control. Upon resuming automatic control, after a few seconds, the fan
PWM is now properly restored, to what the PID loop wanted it to be at.

Signed-off-by: Josh Lehan <krellan@google.com>
Signed-off-by: Jason Ling <jasonling@google.com>
Change-Id: I46fc65d6b931755d51093ea475c64cf5e3e6bacb
diff --git a/test/pid_fancontroller_unittest.cpp b/test/pid_fancontroller_unittest.cpp
index 866b743..883ca84 100644
--- a/test/pid_fancontroller_unittest.cpp
+++ b/test/pid_fancontroller_unittest.cpp
@@ -171,10 +171,13 @@
     SensorMock* sm1 = reinterpret_cast<SensorMock*>(s1.get());
     SensorMock* sm2 = reinterpret_cast<SensorMock*>(s2.get());
 
+    EXPECT_CALL(z, getRedundantWrite())
+        .WillOnce(Return(false))
+        .WillOnce(Return(false));
     EXPECT_CALL(z, getSensor(StrEq("fan0"))).WillOnce(Return(s1.get()));
-    EXPECT_CALL(*sm1, write(0.75));
+    EXPECT_CALL(*sm1, write(0.75, false, _));
     EXPECT_CALL(z, getSensor(StrEq("fan1"))).WillOnce(Return(s2.get()));
-    EXPECT_CALL(*sm2, write(0.75));
+    EXPECT_CALL(*sm2, write(0.75, false, _));
 
     // This is a fan PID, so calling outputProc will try to write this value
     // to the sensors.
@@ -207,10 +210,13 @@
     SensorMock* sm1 = reinterpret_cast<SensorMock*>(s1.get());
     SensorMock* sm2 = reinterpret_cast<SensorMock*>(s2.get());
 
+    EXPECT_CALL(z, getRedundantWrite())
+        .WillOnce(Return(false))
+        .WillOnce(Return(false));
     EXPECT_CALL(z, getSensor(StrEq("fan0"))).WillOnce(Return(s1.get()));
-    EXPECT_CALL(*sm1, write(0.5));
+    EXPECT_CALL(*sm1, write(0.5, false, _));
     EXPECT_CALL(z, getSensor(StrEq("fan1"))).WillOnce(Return(s2.get()));
-    EXPECT_CALL(*sm2, write(0.5));
+    EXPECT_CALL(*sm2, write(0.5, false, _));
 
     // This is a fan PID, so calling outputProc will try to write this value
     // to the sensors.
@@ -243,13 +249,50 @@
     double percent = 80;
     double value = percent / 100;
 
+    EXPECT_CALL(z, getRedundantWrite()).WillOnce(Return(false));
     EXPECT_CALL(z, getSensor(StrEq("fan0"))).WillOnce(Return(s1.get()));
-    EXPECT_CALL(*sm1, write(value));
+    EXPECT_CALL(*sm1, write(value, false, _));
 
     // This is a fan PID, so calling outputProc will try to write this value
     // to the sensors.
     p->outputProc(percent);
 }
 
+TEST(FanControllerTest, OutputProc_VerifyRedundantWrites)
+{
+    /* when a zone indicates that redundant writes are enabled
+     * make sure the fan controller honors this by forcing a sensor write
+     */
+    ZoneMock z;
+
+    std::vector<std::string> inputs = {"fan0", "fan1"};
+    ec::pidinfo initial;
+
+    std::unique_ptr<PIDController> p =
+        FanController::createFanPid(&z, "fan1", inputs, initial);
+    EXPECT_FALSE(p == nullptr);
+
+    EXPECT_CALL(z, getFailSafeMode()).WillOnce(Return(false));
+
+    int64_t timeout = 0;
+    std::unique_ptr<Sensor> s1 = std::make_unique<SensorMock>("fan0", timeout);
+    std::unique_ptr<Sensor> s2 = std::make_unique<SensorMock>("fan1", timeout);
+    // Grab pointers for mocking.
+    SensorMock* sm1 = reinterpret_cast<SensorMock*>(s1.get());
+    SensorMock* sm2 = reinterpret_cast<SensorMock*>(s2.get());
+
+    EXPECT_CALL(z, getRedundantWrite())
+        .WillOnce(Return(true))
+        .WillOnce(Return(true));
+    EXPECT_CALL(z, getSensor(StrEq("fan0"))).WillOnce(Return(s1.get()));
+    EXPECT_CALL(*sm1, write(0.5, true, _));
+    EXPECT_CALL(z, getSensor(StrEq("fan1"))).WillOnce(Return(s2.get()));
+    EXPECT_CALL(*sm2, write(0.5, true, _));
+
+    // This is a fan PID, so calling outputProc will try to write this value
+    // to the sensors.
+    p->outputProc(50.0);
+}
+
 } // namespace
 } // namespace pid_control