/* Gesture Mouse - Control your computer with a glove
   Code by - TheRazerEdge
*/

// Include libraries
#include <Wire.h>
#include <I2Cdev.h>
#include <MPU6050.h>
#include <Mouse.h>

// Gyro variables
MPU6050 mpu;
int16_t gx, gy, gz; // Define gyro output variables
int vx, vy;      // Define pointer displacement

// Flex variables
// Define flex sensor pins
const int indexPin = A0;
const int middlePin = A1;

int valIndex, valMiddle; // Define sensor output values
int sense = 600;     // Define pointer senstivity value (increase for less senstivity)

// Define flex sensor threshold and flag
int buffIndex = 850;
int buffMiddle = 850;
bool flagIndex = 0;
bool flagMiddle = 0;

// Define rate of refresh
int rate = 20;

// setup() initializes I2C communication, MPU-6050 module connection, HID mouse functionality and serial communication.
void setup()
{
  Wire.begin();
  mpu.initialize();
  Mouse.begin();
  Serial.begin(9600); // Begin serial communication for reading sensor readings
}

// loop() executes continuously the whole functionality
void loop()
{
  moveMouse();
  clickMouse();
  printValues();
  delay(rate);
}

// moveMouse() gets rotational values from the gyro sensor and feeds them into the variable assigned.
// Then, it converts the output values into pointer displacement values in the form of x and y displacement coordinates.
// In the end, it calls the Mouse.move() function, which moves according to the displacement values calculated.
void moveMouse()
{
  if (flagIndex == 0 && flagMiddle == 0)
  {
    mpu.getRotation(&gx, &gy, &gz); // Get rotation values from gyroscope

    // Convert output values to pointer displacement
    vx = -(gx + 200) / sense; // Here, change the '200' & '30' values to the approximate +ve values
    vy = (gz + 30) / sense;   // of the values shown by the gyroscope when in rest on the serial monitor.

    Mouse.move(vx, vy); // Move mouse according to gyro rotation
  }
}

// clickMouse() uses values from the flex sensors to detect change in bend and take actions
// defined in the clickIndex() and clickMiddle() functions. Both functions are assigned to
// the respective flex sensor.
void clickMouse()
{
  // Read flex sensor values
  valIndex = analogRead(indexPin);
  valMiddle = analogRead(middlePin);

  // Perform mouse functions
  clickIndex();
  clickMiddle();
}

// clickIndex() makes sure of left mouse clicks based on state of the index finger flex sensor
void clickIndex()
{
  if (flagIndex == 0)
  {
    if (valIndex > buffIndex)
    {
      flagIndex = 1;
      Mouse.press(MOUSE_LEFT);
      Mouse.release(MOUSE_LEFT);
    }
  }
  else if (flagIndex == 1)
  {
    if (valIndex < buffIndex)
    {
      flagIndex = 0;
    }
  }
}

// clickMiddle() makes sure of right mouse clicks based on state of the middle finger flex sensor
void clickMiddle()
{
  if (flagMiddle == 0)
  {
    if (valMiddle > buffMiddle)
    {
      flagMiddle = 1;
      Mouse.press(MOUSE_RIGHT);
      Mouse.release(MOUSE_RIGHT);
    }
  }
  else if (flagMiddle == 1)
  {
    if (valMiddle < buffMiddle)
    {
      flagMiddle = 0;
    }
  }
}

void printValues()
{
  Serial.print("\n");
  Serial.print("Gyroscope values - gx=");
  Serial.print(gx);
  Serial.print(" gy=");
  Serial.print(gy);
  Serial.print(" gz=");
  Serial.print(gz);
  Serial.print("\n");

  Serial.print("Pointer displacement - vx=");
  Serial.print(vx);
  Serial.print(" vy=");
  Serial.print(vy);
  Serial.print("\n");

  Serial.print("\n");
  Serial.print("Index Flex value: ");
  Serial.print(valIndex);
  Serial.print("\n");
  Serial.print("Middle Flex value: ");
  Serial.print(valMiddle);
  Serial.print("\n");
}
