// screen init
#include <Wire.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"

// 0X3C+SA0 - 0x3C or 0x3D
#define I2C_ADDRESS 0x3C

// Define proper RST_PIN if required.
#define RST_PIN -1

SSD1306AsciiWire oled;
// end of screen init

//init button 1
const int buttonPin1 = p20;
const int relay1 = p22;
int oldValue1 = HIGH; // default/idle value for pin 4 is high.
// end of button 1 init

//init button 2
const int buttonPin2 = p21;
const int relay2 = p26;
int oldValue2 = HIGH; // default/idle value for pin 4 is high.
// end of button 1 init

int newValue1 = HIGH;
int newValue2 = HIGH;

int splash = 0; 

#define MENU_SIZE 3
char *menu[MENU_SIZE] = { "RAZ compteur", "long. / tour", "Exit"};
int cursor = 0;

int chaincounter = 0; // should be in NVRAM.....
float chainlength = 0.3; // should be in NVRAM.....

void setup() 
{
  Serial1.begin(115200);
  Serial1.println("Hello, Raspberry Pi Pico!");
  Serial1.println("Press a button.");

  // Initialize the pin for reading button 1.
  pinMode(buttonPin1, INPUT_PULLUP);
  pinMode(p22, OUTPUT);
  digitalWrite(relay1, LOW);

  // Initialize the pin for reading button 2.
  pinMode(buttonPin2, INPUT_PULLUP);
  pinMode(p26, OUTPUT);
  digitalWrite(relay2, LOW);

  //// setup screen
  Wire.begin();
  Wire.setClock(400000L);

 #if RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS, RST_PIN);
 #else // RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS);
 #endif // RST_PIN >= 0
  
  oled.clear();
  oled.setFont(System5x7);
  oled.setCursor(0, 0);
  oled.print("Compteur de chaine:");
  oled.setCursor(40, 1);
  oled.print("Pret!");
  oled.setCursor(0, 3);
  oled.print("Left = UP");
  oled.setCursor(0, 5);
  oled.print("Right = DOWN");
  oled.setCursor(0, 7);
  oled.print("Left + Right = MENU");
   //// end of screen setup

}

void loop() 
{
  int nosetup = 0;  // normally we are not in setup mode....
  int keypressed = 0; // 0= no key, 1 = up, 2 = down, 3 = both keys --> setup

  newValue1 = digitalRead(buttonPin1);
  newValue2 = digitalRead(buttonPin2);
  keypressed = (newValue1 == LOW) + (2*(newValue2 == LOW));

  if (keypressed > 0){
    if (splash == 0){ // cleanup splash screen on the first key pressed
    splash = 1;
    oled.clear();
    oled.setCursor(0,7);
    oled.print("UP               DOWN");
    newValue1 = HIGH;
    newValue2 = HIGH;
    } 
  }

  //////////////////////////////////////////////////////////
  //****************** Menu Setup **************************
  //////////////////////////////////////////////////////////
  if (keypressed == 3){ // Enter in setup mode if the two keys are pressed
    digitalWrite(relay1, LOW);  //stop up & down operations
    digitalWrite(relay2, LOW);
    oled.clear();
    nosetup = 1;
    for(int i=0; i < 20; i++){  // wait 2 seconds before entering setup
      if ((digitalRead(buttonPin1) == HIGH) && (digitalRead(buttonPin2) == HIGH)){
        nosetup = 0;
        newValue1 = HIGH;
        newValue2 = HIGH;
        break;
      } 
      delay(100);
    }

    if(nosetup == 1){
      showMenu();

      for(;;){

       while((digitalRead(buttonPin1) == LOW) && (digitalRead(buttonPin2) == LOW)){
         delay(100); // wait until all buttons are released
        }

        int choice = (digitalRead(buttonPin1) == LOW);
        int exec = (digitalRead(buttonPin2) == LOW);

        if (exec == 1){ // button 2 pressed - execute the choice
          exec = 0;
          if(cursor == (MENU_SIZE -1)){ // EXIT setup is selected : return to normal operations
            oled.clear();
            oled.setCursor(0,7);
            oled.print("UP               DOWN");
            newValue1 = HIGH;
            newValue2 = HIGH;
            break;
          }  //exit setup
          executeChoice(cursor);
          while(digitalRead(buttonPin2) == LOW){
            delay(100); // wait until button 2 is released
          }

        }
        if (choice == 1){ //button 1 pressed - set cursor on next menu entry
          oled.setCursor(0,cursor*2);
          oled.print(' ');
          cursor = cursor +1;
          if (cursor >= MENU_SIZE) cursor = 0;
          oled.setCursor(0,cursor*2);
          oled.print('>');
          choice = 0;
          while(digitalRead(buttonPin1) == LOW){
            delay(100); // wait until button 1 is released
          }
        }
        delay(100);
      }
    }
  } //*************** exit setup *****************
  
  // Check if the value was changed,
  // by comparing it with the previous value.
  if(newValue1 != oldValue1)  // button 1 pressed
  {
    if(newValue1 == LOW)  digitalWrite(relay1, HIGH);
    else  digitalWrite(relay1, LOW);
    // Remember the value for the next time.
    oldValue1 = newValue1;
  }

  if(newValue2 != oldValue2)  // button 2 pressed
  {
    if(newValue2 == LOW)  digitalWrite(relay2, HIGH);
    else  digitalWrite(relay2, LOW);
    // Remember the value for the next time.
    oldValue2 = newValue2;
  }

  // normally chaincounter is updated automatically on each winch turn. we only have to care about the direction (up or down) 
  chaincounter = chaincounter + (oldValue2 == LOW) - (oldValue1 == LOW);

  if(splash == 1){  // if current mode is normal operation, display chain counter in big chars.
    oled.setCursor(40, 2);
    oled.setFont(lcdnums14x24);
    oled.print(round(chaincounter*chainlength), 0); oled.print("   ");
    oled.setFont(System5x7);
    oled.setCursor(0,7);
    oled.print("UP               DOWN");
  }
  // Slow down for debouncing the buttons.
  delay(100);
}

//*****************************************
//*** Clear display and show the Setup menu.
//******************************************
void showMenu() {

  oled.clear();
  oled.setFont(System5x7);
  
  // show menu items:
  for (int i = 0; i<MENU_SIZE; i++) {
    oled.setCursor(10, i*2);
    oled.print(menu[i]);  
    if( i == 0) {
      oled.print(" (");
      oled.print(round(chaincounter*chainlength), 0);
      oled.print(")");
    }
    if( i == 1) {
      oled.print(" (");
      oled.print(chainlength);
      oled.print(")");
    }

  }
  oled.setCursor(0,7);
  oled.print("Choix              OK");
  oled.setCursor(0,0);
  oled.print('>');
  cursor = 0;
}

//*****************************************
//*** Compute the chain lenght
//******************************************
void circonference() {

  oled.clear();
  oled.setFont(System5x7);
  oled.setCursor(0, 0);
  oled.print("longueur de chaine"); 
  oled.setCursor(0, 2);
  oled.print("pour un tour de"); 
  oled.setCursor(0, 4);
  oled.print("guindeau:");
  oled.setCursor(50, 6);
  oled.print(chainlength);
  oled.setCursor(0,7);
  oled.print("Choix              OK");

  while(digitalRead(buttonPin2) == LOW){
    delay(100); // wait until all buttons are released
  }
  
  // increase or decrease chain length
  for (;;) {    
    if(digitalRead(buttonPin1) == LOW){ // increase the length of the chain (for one turn)
      chainlength += 0.01;              // 1 cm for each button press
      if (chainlength > 0.90) chainlength = 0.10; // chain length must be between 10 and 90 cm.
      oled.setCursor(50,6);
      oled.print(chainlength);
      while((digitalRead(buttonPin1) == LOW)){  // prevent automatic increase by long pressing the button
        delay(100); // wait until button 1 is released
      }
    }
    
    if(digitalRead(buttonPin2) == LOW){
      break;
    }
    delay(100);
  }
}

//*********************************************************
//*** Execute the task which matches the chosen menu item.
//*********************************************************
void executeChoice(int choice) {
  switch(choice) {
      case 0 :  // reset chain counter
        Serial1.print("Execute choice "); Serial1.print(choice); Serial1.print(" - "); Serial1.println(menu[choice]);
        chaincounter = 0;
        oled.setCursor(10, 0);
        oled.print(menu[0]);  
        oled.print(" (");
        oled.print(round(chaincounter*chainlength), 0);
        oled.print(")    ");
        break;
      case 1 :  // set chain length
        Serial1.print("Execute choice "); Serial1.print(choice); Serial1.print(" - "); Serial1.println(menu[choice]);
        circonference();
        // reset also the chain counter
        chaincounter = 0;
        showMenu();
        break;
      case 2 :
                Serial1.print("Execute choice "); Serial1.print(choice); Serial1.print(" - "); Serial1.println(menu[choice]);
                break;
      case 3 :
                Serial1.print("Execute choice "); Serial1.print(choice); Serial1.print(" - "); Serial1.println(menu[choice]);
                break;
      case 4 :
                Serial1.print("Execute choice "); Serial1.print(choice); Serial1.print(" - "); Serial1.println(menu[choice]);
                break;
      default :
                Serial1.print("Execute choice "); Serial1.print(choice); Serial1.print(" - "); Serial1.println(menu[choice]);
                break;
  }
  
}
BOOTSELLED1239USBRaspberryPiPico©2020RP2-8020/21P64M15.00TTT
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module