RSSI переключатель от MatCat's (на плате от Ardustation2)

Olegos

Некторое время назад стал собирать себе Ardustation, и совершенно случайно наткнулся на интересный проект полностью построенный на аналогичном железе. Это был переключатель сигнала по уровням RSSI. На тот момент у меня уже было собранно несколько лишних экземпляров Ardustation (было дешевле купить детали разом вышло что-то вроде 300р за комплект). По этой причине я немного подредактировал проект, а именно переместил пины для совместимости с платой Ardupilot2.

  1. выходы для управления микросхемой переключения видео выведены на выход серв, сигналы D9 D10
  2. входы RSSI перенесены на AD0 AD1
  3. вход AD_KEY перенесён на AD2





Оригинальный вариант схемы, из него надо взять переключатель видеосигнала
Оригинальный проект fpvlab.com/forums/showthread.php?8692-MatCat-s-DIY…
Интересная страница, на ней описано как вывести сигнал RSSI с приёмника

#include <EEPROM.h>
#include <LiquidCrystal.h>

//Keypad Support
//--------------------------------------------------
int KeyPin = A2;
int adc_key_old = -1;
int adc_key_in = -2;
int adc_key_reading;
long time_detected;
int NUM_KEYS = 5;
int key=-1;
                    //Up,Lft, OK,Rgt,Down
int adc_key_val[5] = {30,160,360,550,780};
int UpButton = 0;
int LeftButton = 1;
int OKButton = 2;
int RightButton = 3;
int DownButton = 4;
int RandomVar = 0;

//Menu Support
//--------------------------------------------------
char MenuItems[][19] = {"Time Information",
                        "Settings",
                        "About"};

char SettingsMenu[][19] = {"Input 1",
                           "Input 2",
                           "Switch %",
                           "Threshold %",
                           "Save Settings",
                           "Reset Settings"};
char SettingsInputMenu[][19] = {"Reverse Scale",
                                "Min. RSSI",
                                "Max. RSSI"};
int SelectedMenu = -1;
int InMenu = 0;

//Display Support
//--------------------------------------------------
int RSpin = 2;
int RWpin = 3;
int Enablepin = 4;
int D4pin = 5;
int D5pin = 6;
int D6pin = 7;
int D7pin = 8;
int delaytime = 400;
int row = 4;
int col = 20;

// Custom LCD Characters
int custom1_Right_Arrow[] = {0x0,0x4,0x6,0x1f,0x1f,0x6,0x4,0x0};
int custom2_Left_Arrow[] = {0x0,0x4,0xc,0x1f,0x1f,0xc,0x4,0x0};
int custom3_Up_Arrow[] = {0x4,0xe,0x1f,0x4,0x4,0x4,0x4,0x4};
int custom4_Down_Arrow[] = {0x4,0x4,0x4,0x4,0x4,0x1f,0xe,0x4};
int custom5_Shaft[] = {0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4};
int custom6_Selector[] = {0x4,0x4,0x6,0x7,0x7,0x6,0x4,0x4};
int custom7_Lock[] = {0x4,0xa,0xa,0xe,0x1f,0x1b,0x1f,0xe};
int buttoncount[5] = {0,0,0,0,0};
//Diversity Support
//--------------------------------------------------
// Configurable parameters
unsigned int RSSICenterPoint = 50;    // 50% mark of RSSI reading
unsigned int RSSIDiffPerc = 5;         // 5% difference before switching can happen
unsigned int RSSIMin[3] = {0,390,390}; // Set no signal mark
unsigned int RSSIMax[3] = {0,633,633}; // Set Full Signal Mark
unsigned int RSSIReverse[3] = {0,1,0};
// Time based variables
unsigned long lastChange;              // Last switch time
unsigned int SecondsOn[3] = {0,0,0};   // Number of seconds each input has been active

// Pin Configurations
int RSSI1 = A0;
int RSSI2 = A1;
int SwitchPinA = 9;
int SwitchPinB = 10;

// Diversity value variables
int DrawNow = 1;
int CurrentInput = 1;
int LockedInput = 0;
int RSSIValues[3] = {0,0,0};
float RSSIVolt[3] = {0.0,0.0,0.0};
int RSSICount = 0;
int VoltCount = 0;
long RSSIAvg[3] = {0,0,0};
int RSSIAvgValue[3] = {0,0,0};

LiquidCrystal lcd(RSpin, RWpin, Enablepin, D4pin, D5pin, D6pin, D7pin);

void setup() {
  // Check Stored Data
  int ReadByte = 255;
  ReadByte = EEPROM.read(0);
  if (ReadByte == 1) {
    RSSICenterPoint = EEPROM.read(1);
    RSSIDiffPerc = EEPROM.read(2);
    RSSIReverse[1] = EEPROM.read(3);
    RSSIReverse[2] = EEPROM.read(4);
    RSSIMin[1] = EEPROM.read(5);
    RSSIMin[2] = EEPROM.read(6);
    RSSIMax[1] = EEPROM.read(7);
    RSSIMax[2] = EEPROM.read(8);
  }
  time_detected = millis();
  pinMode(SwitchPinA,OUTPUT);
  pinMode(SwitchPinB,OUTPUT);
  pinMode(RSSI1,INPUT);
  pinMode(RSSI2,INPUT);
  pinMode(KeyPin,INPUT);
  lcd.begin(col,row);
  defineCharacter(1, custom1_Right_Arrow);
  defineCharacter(2, custom2_Left_Arrow);
  defineCharacter(3, custom3_Up_Arrow);
  defineCharacter(4, custom4_Down_Arrow);
  defineCharacter(5, custom5_Shaft);
  defineCharacter(6, custom6_Selector);
  defineCharacter(7, custom7_Lock);

  lcd.setCursor(0, 1);
  lcd.print("MatCat Groundstation");
  lcd.setCursor(0,2);
  lcd.print("    Version 1.0");
  adc_key_old = analogRead(KeyPin);
  delay(2000);
  lcd.clear();
  lcd.setCursor(0,0);
}
void loop() {
  adc_key_reading = analogRead(KeyPin);         // Read for keypress
  adc_key_reading = get_key(adc_key_reading);
  if (adc_key_reading != adc_key_old) {         // Debounce routine
    time_detected = millis();
  }
  long timediff = millis() - time_detected;
  if (timediff > 70) {
    adc_key_in = adc_key_reading;
    time_detected = millis() + 150;  // This makes sure if button is held it doesn't go crazy fast
    if (adc_key_in != -1) {
      buttoncount[adc_key_in]+=1;
    }
  }
    adc_key_old = adc_key_reading;

    if (InMenu == 0 || InMenu == 4) {    // Button handling while in no menus
      if (adc_key_in == OKButton) {      // Go in Menu
        SelectedMenu = 0;
        InMenu = 1;
        PrintMenu();
        goto EndButtons;
      }
      if (adc_key_in == LeftButton) {        // Lock Input 1
        LockedInput = 1;
        SetInput(1);
        DrawNow = 2;
        if (InMenu == 0) {
          lcd.setCursor(0,2);
          lcd.write(7);
          lcd.print("Lock Source 1");
          DrawNow = 1;
        }
      }
      if (adc_key_in == RightButton) {        // Lock Input 2
        LockedInput = 2;
        SetInput(2);
        DrawNow = 2;
        if (InMenu == 0) {
          lcd.setCursor(0,2);
          lcd.write(7);
          lcd.print("Lock Source 2");
          DrawNow = 1;
        }
      }
      if (adc_key_in == DownButton || adc_key_in == UpButton) {        // Unlock Inputs
        LockedInput = 0;
        DrawNow = 1;
      }

    }
    if (InMenu == 1) {                  // Button handling for Menu 1
        if (adc_key_in == LeftButton) {     // Exit menu
          SelectedMenu = -1;
          InMenu = 0;
          lcd.clear();
          DrawNow=1;
          goto EndButtons;
        }
       if (adc_key_in == RightButton) { // Go to specified menu option
         switch (SelectedMenu) {
           case 0:
           // Time Info
           InMenu=4;
           lcd.clear();
           DrawNow=2;
           goto EndButtons;
           break;
           case 1:
           // Settings Menu
           InMenu=2;
           SelectedMenu=0;
           PrintMenu();
           goto EndButtons;
           break;
           case 2:
           // About Menu
           InMenu=99;
           lcd.clear();
           break;
         }
       }
    }
    if (InMenu == 1 || InMenu == 2 || InMenu == 5 || InMenu == 6 || InMenu == 99) {
      if (adc_key_in == OKButton) {     // Exit menu
        SelectedMenu = -1;
        InMenu = 0;
        lcd.clear();
        DrawNow=1;
      }
      if (adc_key_in == RightButton) {      // Select Menu
        if (InMenu == 1) {
        } else {
          switch (InMenu) {
            case 5:  // We are doing Input 1 Setting Menu
              switch (SelectedMenu) {
                case 0:  // Reverse Scaling
                   if (RSSIReverse[1] == 0) {
                     RSSIReverse[1] = 1;
                   } else {
                     RSSIReverse[1] = 0;
                   }
                   PrintMenu();
                   break;
                case 1:  // Min
                  RSSIMin[1]+=1;
                  if (RSSIMin[1] > 1023) {
                    RSSIMin[1] = 1023;
                  }
                  PrintMenu();
                  break;
                case 2:  // Max
                  RSSIMax[1]+=1;
                  if (RSSIMax[1] > 1023) {
                    RSSIMax[1] = 1023;
                  }
                  PrintMenu();
                  break;
              }
              break;
            case 6:    // We are Doing Input 2 Setting Menu
              switch (SelectedMenu) {
                case 0:  // Reverse Scaling
                   if (RSSIReverse[2] == 0) {
                     RSSIReverse[2] = 1;
                   } else {
                     RSSIReverse[2] = 0;
                   }
                   PrintMenu();
                   break;
                case 1:  // Min
                  RSSIMin[2]+=1;
                  if (RSSIMin[2] > 1023) {
                    RSSIMin[2] = 1023;
                  }
                  PrintMenu();
                  break;
                case 2:  // Max
                  RSSIMax[2]+=1;
                  if (RSSIMax[2] > 1023) {
                    RSSIMax[2] = 1023;
                  }
                  PrintMenu();
                  break;
              }
              break;
            case 2:  // We are in Settings Menu
          switch (SelectedMenu) {
            case 0:  // Input 1 Settings
             InMenu=5;
             SelectedMenu=0;
             PrintMenu();
            break;
            case 1:  // Input 2 Settings
             InMenu=6;
             SelectedMenu=0;
             PrintMenu();
            break;
            case 2:  // Switch %
              RSSIDiffPerc+=1;
              if (RSSIDiffPerc > 100) {
                RSSIDiffPerc = 100;
              }
                PrintMenu();

            break;
            case 3:  // Thres. %
              RSSICenterPoint+=1;
              if (RSSICenterPoint > 100) {
                RSSICenterPoint = 100;
              }
                PrintMenu();
            break;
            case 4:  // Save Settings
              EEPROM.write(0,1);
              EEPROM.write(1,RSSICenterPoint);
              EEPROM.write(2,RSSIDiffPerc);
              EEPROM.write(3,RSSIReverse[1]);
              EEPROM.write(4,RSSIReverse[2]);
              EEPROM.write(5,RSSIMin[1]);
              EEPROM.write(6,RSSIMin[2]);
              EEPROM.write(7,RSSIMax[1]);
              EEPROM.write(8,RSSIMax[2]);
              lcd.setCursor(1,0);
              lcd.print("Setting: Saved");
            break;
            case 5:  // Reset Settings
              RSSICenterPoint=50;
              RSSIDiffPerc=5;
              RSSIReverse[1] = 1;
              RSSIReverse[2] = 0;
              RSSIMin[1] = 390;
              RSSIMin[2] = 390;
              RSSIMax[1] = 633;
              RSSIMax[2] = 633;
              lcd.setCursor(1,0);
              lcd.print("Setting: Reset");
            break;
          }
        break;
        }
      }
      goto EndButtons;
      }
      if (adc_key_in == LeftButton) {
       if ( InMenu == 2 && SelectedMenu != 2 && SelectedMenu!=3) { // Return to Main Menu
          SelectedMenu = 0;
          InMenu = 1;
          PrintMenu();
          goto EndButtons;
        } else {
          if (InMenu==2) {  // We are in Setting Menu
            switch (SelectedMenu) {
            case 2:  // Switch %
              RSSIDiffPerc-=1;
              if (RSSIDiffPerc < 0 || RSSIDiffPerc > 100) {
                RSSIDiffPerc = 0;
              }
                PrintMenu();
            break;
            case 3:  // Thres. %
              RSSICenterPoint-=1;
              if (RSSICenterPoint < 0 || RSSICenterPoint > 100) {
                RSSICenterPoint = 0;
              }
                PrintMenu();
            break;
          }

          } else {
            if (InMenu==5) {  // We are in Input 1 menu
              switch (SelectedMenu) {
                case 0:  // Reverse Scaling
                   if (RSSIReverse[1] == 0) {
                     RSSIReverse[1] = 1;
                   } else {
                     RSSIReverse[1] = 0;
                   }
                   PrintMenu();
                   break;
                case 1:  // Min
                  RSSIMin[1]-=1;
                  if (RSSIMin[1] < 0) {
                    RSSIMin[1] = 0;
                  }
                  PrintMenu();
                  break;
                case 2:  // Max
                  RSSIMax[1]-=1;
                  if (RSSIMax[1] < 0) {
                    RSSIMax[1] = 0;
                  }
                  PrintMenu();
                  break;
              }
            } else {
              if (InMenu==6) {  // We are in Input 2 Menu
                switch (SelectedMenu) {
                case 0:  // Reverse Scaling
                   if (RSSIReverse[2] == 0) {
                     RSSIReverse[2] = 1;
                   } else {
                     RSSIReverse[2] = 0;
                   }
                   PrintMenu();
                   break;
                case 1:  // Min
                  RSSIMin[2]-=1;
                  if (RSSIMin[2] < 0) {
                    RSSIMin[2] = 0;
                  }
                  PrintMenu();
                  break;
                case 2:  // Max
                  RSSIMax[2]-=1;
                  if (RSSIMax[2] < 0) {
                    RSSIMax[2] = 0;
                  }
                  PrintMenu();
                  break;
              }

              } else {
              }
            }
          }
        }
      }
      if (adc_key_in == DownButton) {   // Scroll Down menu
        if ( (SelectedMenu == 2 && InMenu==1) || (SelectedMenu == 5 && InMenu==2) || (SelectedMenu == 2 && (InMenu == 5 || InMenu==6))) {
          SelectedMenu = 0;
        } else {
          SelectedMenu+=1;
        }
        PrintMenu();
      }
      if (adc_key_in == UpButton) {    // Scroll Up Menu
        if (SelectedMenu == 0) {
          switch (InMenu) {
            case 1:
              SelectedMenu = 2;
            break;
            case 2:
              SelectedMenu = 5;
            break;
            case 5:
              SelectedMenu = 2;
            break;
            case 6:
              SelectedMenu = 2;
            break;
          }
        } else {
          SelectedMenu-=1;
        }
        PrintMenu();
      }
    }
  EndButtons:

  RSSICount+=1;                            // Set counter for averaging
  RSSIValues[1] = analogRead(RSSI1);       // Get raw RSSI voltage
  RSSIValues[2] = analogRead(RSSI2);

  RSSIVolt[1] = (float)RSSIValues[1] * 0.0049;    // Store actual voltage value
  RSSIVolt[2] = (float)RSSIValues[2] * 0.0049;    // Store actual voltage value


  // Check for Reverse Scaling and adjust
  for (int a=1;a < 3;a++) {
    if (RSSIReverse[a]) {
      if (RSSIValues[a] < 5) {
        RSSIValues[a] = 1023;
      }
      RSSIValues[a] = map(RSSIValues[a],1023,0,0,1023);
    }
    // Do a quick auto-calibration check on RSS Max
    if (RSSIValues[a] > RSSIMax[a]) {
      RSSIMax[a] = RSSIValues[a];
    }
    RSSIValues[a] = map(RSSIValues[a],RSSIMin[a],RSSIMax[a],0,100);
  }

  // Do a quick check for out of bounds values
  if (RSSIValues[1] < 0) {RSSIValues[1] = 0;}
  if (RSSIValues[2] < 0) {RSSIValues[2] = 0;}
  if (RSSIValues[1] > 100) {RSSIValues[1] = 100;}
  if (RSSIValues[2] > 100) {RSSIValues[2] = 100;}

  RSSIAvg[1]+= RSSIValues[1];              // Add up for average
  RSSIAvg[2]+= RSSIValues[2];

  if (RSSICount == 200) {                  // Sample from an average of 200 RSSI readings
    VoltCount+=1;
    RSSIAvgValue[1] = RSSIAvg[1]/200;
    RSSIAvgValue[2] = RSSIAvg[2]/200;
    RSSICount = 0;                         // Reset the RSSI Counter and averages
    RSSIAvg[1] = 0;
    RSSIAvg[2] = 0;

    if (VoltCount == 3) {
      if (InMenu==99) {  // Display About
       lcd.setCursor(0,0);
       lcd.print("  MatCat GS v1.00");
       lcd.setCursor(0,2);
       lcd.print("  Arduino Powered");
       lcd.setCursor(0,3);
       lcd.print("     Diversity");
      }
    if (VoltCount == 3 || DrawNow == 1) {  // Purpose here is to not update the screen so fast that you can't read the value
      if (InMenu == 0) {
        lcd.setCursor(0,0);                    // Print RSSI data to screen
        if (CurrentInput == 1) {
          if (LockedInput == 1) {
            lcd.write(7);
          } else {
            lcd.write(1);
          }
        } else {
          lcd.print(" ");
         }
        lcd.print("RSSI 1: ");
        lcd.setCursor(9,0);
        lcd.print("   ");
        lcd.setCursor(9,0);
        lcd.print(RSSIAvgValue[1]);
        lcd.print("%");
        lcd.setCursor(0,1);
        if (CurrentInput == 2) {
          if (LockedInput == 2) {
            lcd.write(7);
          } else {
            lcd.write(1);
          }
        } else {
          lcd.print(" ");
        }

        lcd.print("RSSI 2: ");
        lcd.setCursor(9,1);
        lcd.print("   ");
        lcd.setCursor(9,1);
        lcd.print(RSSIAvgValue[2]);
        lcd.print("%");
        lcd.setCursor(0,2);
        if (LockedInput == 0) {
          lcd.print("Video Source ");
          lcd.print(CurrentInput);
          lcd.print("  ");
        } else {
          lcd.write(7);
          lcd.print("Locked Input ");
          lcd.print(LockedInput);
        }
        DrawNow = 0;
      }
    }
    // Print current voltage too
      VoltCount = 0;
      if (InMenu == 0) {
        printFloat(RSSIVolt[1],2,15,0);
        lcd.print("v");
        printFloat(RSSIVolt[2],2,15,1);
        lcd.print("v");
      }
    }
  }
    // Lets calcualte some time here
    unsigned long CurrentTime = millis();
    unsigned long TimeDifference = CurrentTime - lastChange;
    TimeDifference = TimeDifference / 1000;  // Convert to seconds
    SecondsOn[0]=TimeDifference;

    // Do we need to change inputs?

    // Calculate RSSI Difference
    int RSSIDifference = RSSIAvgValue[1] - RSSIAvgValue[2];
    RSSIDifference = abs(RSSIDifference);

    if (RSSIAvgValue[1] > RSSIAvgValue[2]) {
      // Next we want to make sure the other input is already active, and the difference
      // is greater then 5% or the other RSSI is lower then roughly 50%, and that an input is not locked on
      if (LockedInput == 0 && CurrentInput == 2 && (RSSIAvgValue[2] < RSSICenterPoint || RSSIDifference > RSSIDiffPerc)) {
        // Switch from Input 2 to Input 1
        SetInput(1);
        if (InMenu == 0) {
          lcd.setCursor(0,2);
          lcd.print("Video Source 1");
        }
        // Store time of the change
        lastChange = millis();
      }
    } else {
      if (LockedInput == 0 && CurrentInput == 1 && (RSSIAvgValue[1] < RSSICenterPoint || RSSIDifference > RSSIDiffPerc)) {
        //Switch from Input 1 to Input 2
        SetInput(2);
        if (InMenu == 0) {
          lcd.setCursor(0,2);
          lcd.print("Video Source 2");
        }
        // Store time of the change
        lastChange = millis();
      }
    }

    if (InMenu == 4) {  // Time Info Screen
      if (VoltCount==0 || DrawNow==2) {  // Only want to do it just after a cycle
        DrawNow=0;  // Reset draw immediately flag
        int DrewInd = 0;  // Indicator Drawn Flag
        lcd.setCursor(0,0);
        if (LockedInput == 1) {
            lcd.write(7);
            DrewInd=1;
        }
        if (CurrentInput == 1 && LockedInput == 0) {
            lcd.write(6);
            DrewInd=1;
        }
        if (!DrewInd) {
          lcd.print(" ");
        }
        DrewInd = 0;
        lcd.print("RSSI 1      ");
        if (LockedInput == 2) {
            lcd.write(7);
            DrewInd = 1;
        }
        if (CurrentInput == 2 && LockedInput == 0) {
            lcd.write(6);
            DrewInd = 1;
        }
        if (!DrewInd) {
          lcd.print(" ");
        }
        DrewInd = 0;
        lcd.print("RSSI 2");
        lcd.setCursor(1,1);
        lcd.print(RSSIAvgValue[1]);
        lcd.print("%");
        lcd.setCursor(13,1);
        lcd.print(RSSIAvgValue[2]);
        lcd.print("%");
        int Seconds[2];
        int Minutes[2];
        int Hours[2];
        if (CurrentInput == 1) {
          Seconds[0] = SecondsOn[0] + SecondsOn[1];
          Seconds[1] = SecondsOn[2];
        } else {
          Seconds[0] = SecondsOn[1];
          Seconds[1] = SecondsOn[0] + SecondsOn[2];
        }

        //Calculate the time
        Minutes[0] = Seconds[0]/60;
        Minutes[1] = Seconds[1]/60;
        Seconds[0] = Seconds[0] % 60;
        Seconds[1] = Seconds[1] % 60;
        Hours[0] = Minutes[0] / 60;
        Hours[1] = Minutes[1] / 60;
        Minutes[0] = Minutes[0] % 60;
        Minutes[1] = Minutes[1] % 60;
        lcd.setCursor(1,2);
        if (Hours[0] > 0) {
          lcd.print(Hours[0]);
          lcd.print("h");
        }
        if (Minutes[0] > 0) {
          lcd.print(Minutes[0]);
          lcd.print("m");
        }
        if (Seconds[0] > 0) {
          lcd.print(Seconds[0]);
          lcd.print("s");
        }
        lcd.setCursor(13,2);
        if (Hours[1] > 0) {
          lcd.print(Hours[1]);
          lcd.print("h");
        }
        if (Minutes[1] > 0) {
          lcd.print(Minutes[1]);
          lcd.print("m");
        }
        if (Seconds[1] > 0) {
          lcd.print(Seconds[1]);
          lcd.print("s");
        }

      }
    }
    adc_key_in = -1;    // Make sure we don't do lots of button triggers

  }

void printFloat(float value, int places, int lcdCol, int lcdRow) {
  // this is used to cast digits
  int digit;
  float tens = 0.1;
  int tenscount = 0;
  int i;
  float tempfloat = value;

    // make sure we round properly. this could use pow from , but doesn't seem worth the import
  // if this rounding step isn't here, the value  54.321 prints as 54.3209

  // calculate rounding term d:   0.5/pow(10,places)
  float d = 0.5;
  if (value < 0)
    d *= -1.0;
  // divide by ten for each decimal place
  for (i = 0; i < places; i++)
    d/= 10.0;
  // this small addition, combined with truncation will round our values properly
  tempfloat +=  d;

  // first get value tens to be the large power of ten less than value
  // tenscount isn't necessary but it would be useful if you wanted to know after this how many chars the number will take

  if (value < 0)
    tempfloat *= -1.0;
  while ((tens * 10.0) <= tempfloat) {
    tens *= 10.0;
    tenscount += 1;
  }


  // write out the negative if needed
   lcd.setCursor(lcdCol,lcdRow);
  if (value < 0)
    lcd.print('-');

  if (tenscount == 0)
    lcd.print(0, DEC);

  for (i=0; i< tenscount; i++) {
    digit = (int) (tempfloat/tens);
    lcd.print(digit, DEC);
    tempfloat = tempfloat - ((float)digit * tens);
    tens /= 10.0;
  }

  // if no places after decimal, stop now and return
  if (places <= 0)
    return;

  // otherwise, write the point and continue on
  lcd.print('.');

  // now write out each decimal place by shifting digits one by one into the ones place and writing the truncated value
  for (i = 0; i < places; i++) {
    tempfloat *= 10.0;
    digit = (int) tempfloat;
    lcd.print(digit,DEC);
    // once written, subtract off that digit
    tempfloat = tempfloat - (float) digit;
  }
}
int get_key(unsigned int input) {
  int k;
  for (k = 0; k < NUM_KEYS; k++) {
    if (input < adc_key_val[k]) {
      return k;
    }
  }
    k = -1;
  return k;
}
void PrintMenu(void) {
  /* Menu Layout
    0 1 2 3 4 5 6 7 8 910111213141516171819
  0 /             M a i n   M e n u
  1 >   S e l e c t e d   M e n u   I t e m
  2 |   N o r m a l   m e n u   i t e m
  3 \   N o r m a l   m e n u   i t e m
  */
  int menuSize;
  lcd.clear();
  lcd.setCursor(1,0);
  lcd.print("                   ");
  lcd.setCursor(1,0);
  switch (InMenu) {
    case 1:
      menuSize = sizeof(MenuItems) / (sizeof(char) * 19);
      lcd.print("   Main Menu");
    break;
    case 2:
      menuSize = sizeof(SettingsMenu) / (sizeof(char) * 19);
      switch (SelectedMenu) {
        case 2:
        lcd.print("Setting: [");
        lcd.print(RSSIDiffPerc);
        lcd.print("%]");
        break;
        case 3:
        lcd.print("Setting: [");
        lcd.print(RSSICenterPoint);
        lcd.print("%]");
        break;
      default:
        lcd.print(" Settings Menu");
        break;
      }
    break;
    case 5:
      menuSize = sizeof(SettingsInputMenu) / (sizeof(char) * 19);
      switch (SelectedMenu) {
        case 0:
        lcd.print("Setting: [");
        if (RSSIReverse[1]) {
          lcd.print("YES");
        } else {
          lcd.print("NO");
        }
        lcd.print("]");
        break;
        case 1:
        lcd.print("Setting: [");
        lcd.print(RSSIMin[1]);
        lcd.print("]");
        break;
        case 2:
        lcd.print("Setting: [");
        lcd.print(RSSIMax[1]);
        lcd.print("]");
        break;

      default:
        lcd.print(" Input Menu");
        break;
      }
      break;
    case 6:
      menuSize = sizeof(SettingsInputMenu) / (sizeof(char) * 19);
      switch (SelectedMenu) {
        case 0:
        lcd.print("Setting: [");
        if (RSSIReverse[2]) {
          lcd.print("YES");
        } else {
          lcd.print("NO");
        }
        lcd.print("]");
        break;
        case 1:
        lcd.print("Setting: [");
        lcd.print(RSSIMin[2]);
        lcd.print("]");
        break;
        case 2:
        lcd.print("Setting: [");
        lcd.print(RSSIMax[2]);
        lcd.print("]");
        break;

      default:
        lcd.print(" Input Menu");
        break;
      }
    break;
  }
  if (menuSize > 3 && SelectedMenu > 1) {
    lcd.setCursor(0,0);
    lcd.write(3);
  }
  int MenuPointers[3];
  if (SelectedMenu < 2 || menuSize==3) {
    MenuPointers[0] = 0;
    MenuPointers[1] = 1;
    MenuPointers[2] = 2;
  } else {
    if (((menuSize - (SelectedMenu+1)) < 2) && menuSize > 3 ) {
      MenuPointers[0] = menuSize-3;
      MenuPointers[1] = menuSize-2;
      MenuPointers[2] = menuSize-1;
    } else {
      MenuPointers[0] = SelectedMenu -1;
      MenuPointers[1] = SelectedMenu;
      MenuPointers[2] = SelectedMenu +1;
    }
  }

  for (int a=1;a < 4;a++) {
    lcd.setCursor(0,a);
    if (SelectedMenu == MenuPointers[a-1]) {
      lcd.write(6);
    } else {
      lcd.write(5);
    }
    switch (InMenu) {
      case 1:
        lcd.print(MenuItems[MenuPointers[a-1]]);
        break;
      case 2:
        lcd.print(SettingsMenu[MenuPointers[a-1]]);
        break;
      case 5:
        lcd.print(SettingsInputMenu[MenuPointers[a-1]]);
        break;
      case 6:
        lcd.print(SettingsInputMenu[MenuPointers[a-1]]);
        break;

  }

  }
  if (menuSize > 3 && (menuSize - (SelectedMenu + 1)) > 1) {
    lcd.setCursor(0,3);
    lcd.write(4);
  }
}

// Special function to define custom characters for LCD
int defineCharacter(int ascii, int *data) {
    int baseAddress = (ascii * 8) + 64;
    // baseAddress = 64 | (ascii << 3);
    lcd.command(baseAddress);
    for (int i = 0; i < 8; i++)
        lcd.write(data[i]);
    lcd.command(128);
    return ascii;
}
void SetInput(int input) {
  // Update time data
  SecondsOn[CurrentInput] = SecondsOn[CurrentInput] + SecondsOn[0];
  SecondsOn[0] = 0;
  CurrentInput = input;
  lastChange = millis();
  if (CurrentInput == 1) {
    digitalWrite(SwitchPinB,LOW);
    digitalWrite(SwitchPinA,HIGH);
  } else {
    digitalWrite(SwitchPinA,LOW);
    digitalWrite(SwitchPinB,HIGH);
  }
}