From cc29d520a98bcd918a687ef52b90d17fdefed973 Mon Sep 17 00:00:00 2001
From: Vladimir Zidar <mr_w@mindnever.org>
Date: Tue, 17 Oct 2017 13:06:05 +0200
Subject: [PATCH] LP-544 Add PIOS_Servo_SetActive() API to communicate active
 servo channels from Actuator module to pios_servo driver. pios_servo is not
 allowed to touch inactive outputs.

---
 flight/modules/Actuator/actuator.c            | 23 +++++++++++++++
 flight/pios/common/pios_servo.c               | 28 +++++++++++++++++--
 flight/pios/inc/pios_servo.h                  |  1 +
 .../boards/oplinkmini/firmware/pios_board.c   |  3 +-
 4 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/flight/modules/Actuator/actuator.c b/flight/modules/Actuator/actuator.c
index 7a4f4353b..63666ce1e 100644
--- a/flight/modules/Actuator/actuator.c
+++ b/flight/modules/Actuator/actuator.c
@@ -1062,6 +1062,25 @@ static void actuator_update_rate_if_changed(bool force_update)
     }
 }
 
+static void update_servo_active()
+{
+    /* For each mixer output that is not disabled,
+     * figure out servo address and send allocation map to pios_servo driver.
+     * We need to execute this when either ActuatorSettings or MixerSettings change.
+     */
+    uint32_t servo_active = 0;
+
+    Mixer_t *mixers = (Mixer_t *)&mixerSettings.Mixer1Type;
+
+    for (int ct = 0; ct < MAX_MIX_ACTUATORS; ct++) {
+        if (mixers[ct].type != MIXERSETTINGS_MIXER1TYPE_DISABLED) {
+            servo_active |= 1 << actuatorSettings.ChannelAddr[ct];
+        }
+    }
+
+    PIOS_Servo_SetActive(servo_active);
+}
+
 static void ActuatorSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev)
 {
     ActuatorSettingsGet(&actuatorSettings);
@@ -1070,6 +1089,8 @@ static void ActuatorSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev)
         spinWhileArmed = false;
     }
     actuator_update_rate_if_changed(false);
+
+    update_servo_active();
 }
 
 static void MixerSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev)
@@ -1082,6 +1103,8 @@ static void MixerSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev)
             mixer_settings_count++;
         }
     }
+
+    update_servo_active();
 }
 static void SettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev)
 {
diff --git a/flight/pios/common/pios_servo.c b/flight/pios/common/pios_servo.c
index bcd513032..153cf181d 100644
--- a/flight/pios/common/pios_servo.c
+++ b/flight/pios/common/pios_servo.c
@@ -72,7 +72,8 @@ static uint32_t pios_dshot_t0h_raw;
 static uint32_t pios_dshot_t1h_raw;
 static uint32_t pios_dshot_t_raw;
 
-static bool pios_servo_enabled = true;
+static bool pios_servo_enabled    = true;
+static uint32_t pios_servo_active = 0; // No active outputs by default
 
 #define PIOS_SERVO_TIMER_CLOCK 1000000
 #define PIOS_SERVO_SAFE_MARGIN 50
@@ -83,6 +84,20 @@ static bool pios_servo_enabled = true;
 #define DSHOT_T1H_DIV          1333
 #define DSHOT_NUM_BITS         16
 
+extern void PIOS_Servo_SetActive(uint32_t active)
+{
+    bool enabled = pios_servo_enabled;
+
+    if (enabled) {
+        PIOS_Servo_Disable();
+    }
+
+    pios_servo_active = active;
+
+    if (enabled) {
+        PIOS_Servo_Enable();
+    }
+}
 
 extern void PIOS_Servo_Disable()
 {
@@ -142,6 +157,10 @@ static void PIOS_Servo_SetupBank(uint8_t bank_nr)
             continue;
         }
 
+        if (!(pios_servo_active & (1L << i))) { // This output is not active
+            continue;
+        }
+
         GPIO_InitTypeDef init = chan->pin.init;
 
         switch (bank->mode) {
@@ -345,6 +364,10 @@ static void PIOS_Servo_DShot_Update()
             continue;
         }
 
+        if (!(pios_servo_active & (1L << i))) { // This output is not active
+            continue;
+        }
+
         has_dshot = true;
 
         uint16_t payload = pin->value;
@@ -451,7 +474,8 @@ void PIOS_Servo_Update()
     }
 
     for (uint8_t i = 0; (i < servo_cfg->num_channels); i++) {
-        if (pios_servo_pins[i].bank->mode == PIOS_SERVO_BANK_MODE_SINGLE_PULSE) {
+        if ((pios_servo_active & (1L << i))
+            && (pios_servo_pins[i].bank->mode == PIOS_SERVO_BANK_MODE_SINGLE_PULSE)) {
             /* Update the position */
             const struct pios_tim_channel *chan = &servo_cfg->channels[i];
 
diff --git a/flight/pios/inc/pios_servo.h b/flight/pios/inc/pios_servo.h
index bcc1fff22..76c3e499d 100644
--- a/flight/pios/inc/pios_servo.h
+++ b/flight/pios/inc/pios_servo.h
@@ -41,6 +41,7 @@ enum pios_servo_bank_mode {
 /* Public Functions */
 extern void PIOS_Servo_SetHz(const uint16_t *speeds, const uint32_t *clock, uint8_t banks);
 extern void PIOS_Servo_Set(uint8_t Servo, uint16_t Position);
+extern void PIOS_Servo_SetActive(uint32_t Active);
 extern void PIOS_Servo_Update();
 extern void PIOS_Servo_SetBankMode(uint8_t bank, uint8_t mode);
 extern void PIOS_Servo_DSHot_Rate(uint32_t rate_in_khz);
diff --git a/flight/targets/boards/oplinkmini/firmware/pios_board.c b/flight/targets/boards/oplinkmini/firmware/pios_board.c
index 2de96a068..7f3e8cd11 100644
--- a/flight/targets/boards/oplinkmini/firmware/pios_board.c
+++ b/flight/targets/boards/oplinkmini/firmware/pios_board.c
@@ -336,9 +336,10 @@ void PIOS_Board_Init(void)
         PIOS_Servo_Init(&pios_servo_flexi_cfg);
     }
 
-    // Set bank modes
+    // Set bank modes and activate output. We need to do this here because oplm does not run Actuator module.
     PIOS_Servo_SetBankMode(0, PIOS_SERVO_BANK_MODE_PWM);
     PIOS_Servo_SetBankMode(1, PIOS_SERVO_BANK_MODE_PWM);
+    PIOS_Servo_SetActive(0b11);
 #endif
 
     PIOS_BOARD_IO_Configure_RFM22B();