/*-----------------------------------------------------------------------------------------
 *  This software is in the public domain, furnished "as is", without technical
 *  support, and with no warranty, express or implied, as to its usefulness for
 *  any purpose.
 *
 *  Multiswitch.ino
 *
 *  Multiswitch decoder for 4 switches. RC PWM signal length for each switch must be
 *  half of the previous one.
 *
 *  This multiswitch based on the Yet another Multi Switch - YaMS implementation
 *  of Dirk Wiedemann (www.rc-bastelbu.de), but is not using the servo lib for the
 *  RC-Signal readings. The hardware information of the encoder should taken from
 *  the above referenzed web-location.
 *  The calibration steps of the RC input signals must be done as described
 *  in pwmread_rcfailsafe.ino as well.
 *
 *  Author: Volker Frauenstein
 *  Date: 06/01/2021 Version: 1.2 functionality of hysteresis added for stability reasons
 *                                of switch buttom recognition
 *
 *  Date: 05/01/2021 Version: 1.1 pinout redefinition for migration to ESP32 architecture
 *  Date: 21/12/2020 Version: 1.0 implementation of multiswitch decoder for Arduino Nano
 */

// pinout definitions for the multiswitch
// const int msPin_a = 23;                    // Enginesound on/off -> used ESP32 internal (switchOn[0]), no pinout needed
// const int msPin_b = 22;                    // Horn on/off -> used ESP32 internal (switchOn[1]), no pinout needed
// const int msPin_c = 21;                    // MG sound on/off -> used ESP32 internal (switchOn[2]), no pinout needed
const int msPin_d = 13;                       // Frontlights on/off

// Thresholds to separate every switch state from his neighbors, must be customized for real encoders
// float MS_threshold [17] = { -1.0625, -0.9375, -0.8125, -0.6875, -0.5625, -0.4375, -0.3125, -0.1875, 0,
//                              0.1875,  0.3125,  0.4375,  0.5625,  0.6875,  0.8125,  0.9375,  1.0625 };

// Adapted thresholds for Robbe Terratop with multiswitch
float MS_threshold [17] = { -1.0625, -0.9785, -0.89, -0.765, -0.6275, -0.495, -0.38, -0.2625, -0.095,
                              0.085, 0.23, 0.375, 0.5425, 0.7075, 0.8525, 0.965, 1.0625 };

// generig definitions
int hysteresis = 0;                           // counter for hysteresis
int last_state = 0;                           // switch state of last cycle
const int MSthreshold = 20;                   // threshold for hysteresis
// #define DEBUG_MS 1

// interface definitions to handle Multiswitch states -> definition in main.ino needed
// bool switchOn[4] = {false, false, false, false}; // one bit per switch: engine/horn/gunfire/lights

void setup_MultiSwitch() {

//      pinMode(msPin_a, OUTPUT);             // uncomment because function in SW
//      pinMode(msPin_b, OUTPUT);             // uncomment because function in SW
//      pinMode(msPin_c, OUTPUT);             // uncomment because function in SW
      pinMode(msPin_d, OUTPUT);               // pinout for 1-Relais Modul
}

void close_MultiSwitch() {

//    digitalWrite(msPin_a, LOW);             // close all digital pins
//    digitalWrite(msPin_b, LOW);
//    digitalWrite(msPin_c, LOW);
    digitalWrite(msPin_d, HIGH);              // Switch on defined with pulldown
    for ( int i = 0; i <4 ; i++) {
     switchOn[i] = false;                     // and switch of internal sound functions
     }
}                                             // function close_MultiSwitch closed

void run_MultiSwitch(int ch) {                // function to check states of the multiswitch
                                              // and activate the pinouts if needed
   float  MS_value = RC_in[ch];               // value of used RC channel for multiswitch
   int S_state = 0;                           // value for state of switches (0 to 15)

   for (int i = 0; i <= 15; i++) {            // precalculate switchstate via the thresholds
    if (MS_value > MS_threshold[i] && MS_value <= MS_threshold[i + 1]) S_state = i;
   }

   if ( S_state != last_state) {              // check if switches have changed
    if (hysteresis > MSthreshold) {
      last_state = S_state;                   // yes we change
      hysteresis = 0;
    }
    else {
      S_state = last_state;                   // hysteresis is running, we we change
      hysteresis++;
    }
   }
    else hysteresis = 0;                      // no change triggered

   #ifdef DEBUG_MS
    Serial.print("MS_switch: ");Serial.print(S_state);Serial.print(" changecount: ");Serial.print(hysteresis);
   #endif

   if (S_state > 7) {                         // check state of highes switch
    digitalWrite(msPin_d, LOW);               // and activate pinout
    S_state = S_state - 8;                    // get ready for next switch
    switchOn[3] = true;
    #ifdef DEBUG_MS
    Serial.print(" T,");
    #endif
   }
   else {
    digitalWrite(msPin_d, HIGH);              // switch is off -> deactivate pinout
    switchOn[3] = false;
    #ifdef DEBUG_MS
    Serial.print(" F,");
    #endif
   }

   if (S_state > 3) {                         // check state of next switch
//    digitalWrite(msPin_c, HIGH);
    S_state = S_state - 4;
    switchOn[2] = true;                       // return with global defined bool array
    #ifdef DEBUG_MS
    Serial.print(" T,");
    #endif
   }
   else {
//    digitalWrite(msPin_c, LOW);
    switchOn[2] = false;
    #ifdef DEBUG_MS
    Serial.print(" F,");
    #endif
   }

   if (S_state > 1) {                         // check state of next switch
//    digitalWrite(msPin_b, HIGH);
    S_state = S_state - 2;
    switchOn[1] = true;
    #ifdef DEBUG_MS
    Serial.print(" T,");
    #endif
   }
   else {
//    digitalWrite(msPin_b, LOW);
    switchOn[1] = false;
    #ifdef DEBUG_MS
    Serial.print(" F,");
    #endif
   }

   if (S_state > 0) {                         // check state of lowest switch
//    digitalWrite(msPin_a, HIGH);
    switchOn[0] = true;
    #ifdef DEBUG_MS
    Serial.print(" T,");
    #endif
   }
   else {
//    digitalWrite(msPin_a, LOW);
    switchOn[0] = false;
    #ifdef DEBUG_MS
    Serial.print(" F:");
    #endif
   }                                          // end of switch state check
   #ifdef DEBUG_MS                            // show DEBUG_MS data if needed
    Serial.print(" MSch");Serial.print(": ");
    Serial.print(RC_in[ch]);Serial.print(" ->  ");
    for (int i = 0; i<4; i++){
      Serial.print(switchOn[i]);Serial.print(",");
    }
    Serial.println();
   #endif
}                                             // function run_MultiSwitch closed