/****************************************************************
Project Title:    DC motor speed and direction control
Target Hardware:  ESP32
Summary: This program reads the input from a potentiometer and controls
the speed and direction of a DC motor connected through a L298N motor
driver.
The potentiometer signal input mapped to the motor speed as follows:
55 to 100% commands motor from 0 to 100% forward
45 to 55% commands no speed from motor
45 to 0% commands motor from 0 to 100% reverse
Because of the lack of a DC motor and driver in wokwi, their functions
are emulated using logic gates and LEDs
Green LED is forward
Red LED is reverse
Finally, you can check the serial plotter to monitor the values of
potentiometer input and the PWM duty cycle.
****************************************************************/

// Define pin numbers
#define POT1 27
#define ENA 23
#define IN1 21
#define IN2 22
#define POT2 14
#define ENB 4
#define IN3 15
#define IN4 2


//Define PWM parameters
#define FREQUENCY 1000
#define CHANNEL1 0
#define CHANNEL2 1
#define RESOLUTION 10

//Declare variables
int pot1Input = 0;
int pot2Input = 0;
struct L298N { //Custom data type for motor driver
  int DC;
  bool DIR1;
  bool DIR2;
} ;
L298N motorDriver1, motorDriver2;

//Define custom motor driver control function
L298N potToMotorDriver(int potInput){ 
  //convert pot input to motor driver outputs
  L298N motorDriver; //Declare a structure to return
  if(potInput > 2252){ //Forward direction
    motorDriver.DC = map(potInput,2252,4095,0,1023);
    motorDriver.DIR1 = HIGH;
    motorDriver.DIR2 = LOW;
  }
  else if (potInput < 1843){ //Reverse direction
    motorDriver.DC = map(potInput,0,1843,1023,0);
    motorDriver.DIR1 = LOW;
    motorDriver.DIR2 = HIGH;
  }
  else { //Stopped
    motorDriver.DC = 0;
    motorDriver.DIR1 = LOW;
    motorDriver.DIR2 = LOW;
  }
  return motorDriver;
}

void setup() {
  // configure  PWM outputs
  ledcSetup(CHANNEL1, FREQUENCY, RESOLUTION);
  ledcSetup(CHANNEL2, FREQUENCY, RESOLUTION);
  
  // attach the channels to the GPIO to be controlled
  ledcAttachPin(ENA, CHANNEL1);
  ledcAttachPin(ENB, CHANNEL2);

  //configure direction control pins
  pinMode(IN1,OUTPUT);
  pinMode(IN2,OUTPUT);
  pinMode(IN3,OUTPUT);
  pinMode(IN4,OUTPUT);

  //configure potentiometer input pin
  pinMode(POT1,INPUT);
  pinMode(POT2,INPUT);

  //Start serial port
  Serial.begin(115200);
  Serial.println("Hello, this is ESP32 DC motor control!");
}

void loop() {
  //Read control potentiometer inputs
  pot1Input = analogRead(POT1);
  pot2Input = analogRead(POT2);

  //Calculate duty cycle and direction pin states
  motorDriver1 = potToMotorDriver(pot1Input);
  motorDriver2 = potToMotorDriver(pot2Input);

  //Write values to motor driver output pins
  //Motor driver 1
  ledcWrite(CHANNEL1, motorDriver1.DC);
  digitalWrite(IN1,motorDriver1.DIR1);
  digitalWrite(IN2,motorDriver1.DIR2);
  //Motor driver 2
  ledcWrite(CHANNEL2, motorDriver2.DC);
  digitalWrite(IN3,motorDriver2.DIR1);
  digitalWrite(IN4,motorDriver2.DIR2);
  
  //Print values to serial terminal
  Serial.print("Duty Cycle 1: ");
  Serial.print(motorDriver1.DC);
  Serial.print(" Duty Cycle 2: ");
  Serial.println(motorDriver2.DC);

  delay(250); // loop delay
}