#include <EEPROM.h>
#include <math.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <Adafruit_NeoPixel.h>

Adafruit_SSD1306 display( 128, 64);
String readString , menu_option;
double temp;
float celsius;
const byte adcPin = 3;
volatile double adcReading;
volatile boolean adcDone;
boolean adcStarted;
float temperatureValue;

int  button_3 = 0 ;

char password[8] = "EEE20003";
const float Beta = 3950;
#define VERT_PIN A0
#define HORZ_PIN A1
#define SEL_PIN  28
int horz ;
int vert;
int option = 0;
int  activate_count = 0;
unsigned long  lastbutton_time_3 ;
unsigned long button_time_3 ;
const float GAMMA = 0.7;
const float RL10 = 50;
const int mpuAddress = 0x68;

int choose_user = 0 ;
int count_time_turnon  = 0;
double xByGyro, yByGyro, zByGyro;
double  x_angle, y_angle, z_angle;
double  xOrigin = 25;
double  yOrigin = 32;
double  xAccel_cal, yAccel_cal, zAccel_cal;
int    xAccel_dis, yAccel_dis, zAccel_dis;
const double viewDistance = 150.0;
double voltage, resistance, lux;
int analogValue;
double current_Time, previous_Time, interval_Time ;
double xByAccel, yByAccel, zByAccel;
double x, y, z;
double new_velocityx ;
double old_velocityx = 0;
double new_velocityy = 0;
double old_velocityy = 0;
double new_velocityz = 0 ;
double old_velocityz = 0 ;
int displacement_xcurrent  ;

int displacement_ycurrent ;
int displacement_zcurrent  ;

volatile int dataMessage = 0;
volatile int messageTime = 0;

double checkfall_xAccel ;
double checkfall_yAccel ;
double checkfall_zAccel ;
double total_checkfall;
double A_SVM;
double total_fall_angle;
double check_angle_fall;
double checkfall_roll ;
double checkfall_pitch ;
double total_checkfall_ptandroll ;

double s_total_angle_fall;

int16_t AcX, AcY, AcZ, Temperature, GyX, GyY, GyZ;
volatile boolean check_mpu;
volatile boolean check_pin_mpu;


unsigned long  lastbutton_time_1 ;
unsigned long  button_time_1 ;
unsigned long  lastbutton_time_2 ;
unsigned long  button_time_2;

#define NUM_VERTICES 8
const int triangle_vertex[NUM_VERTICES][3] =
{
  { -16, -16, 16 },     // x, y, z coordination of  the 3D pyramid
  {  26,  0,  16 },
  {  26,  0,  16 },
  { -16,  16, 16 },
  { -16, -16, -1 },
  {  26,  0, -1 },
  {  26,  0, -1 },
  { -16,  16, -1 }
};



int wireframe[NUM_VERTICES][2];



void setup()
{
  pinMode(12, OUTPUT);
  Serial.begin( 115200);
  //request Password
  Serial.println("Enter Password: ");

  //write password to size to EEPROM address 0
  EEPROM.write(0, sizeof(password));
  //write password to EEPROM from 1 onward
  for (int i = 0; i < sizeof(password); i++) {
    EEPROM.write(i + 1, password[i]);
  }

  //password protection function
  checkPassword();
  Serial.println("Please Chooose Follow Option Using Button or Serial Monitor ");
  Serial.println("1/Inital Position ");
  Serial.println("2/Body Temperature");
  Serial.println("3/Fall Detect");

  Wire.begin();

  attachInterrupt(digitalPinToInterrupt(2), next_step, RISING);
  attachInterrupt(digitalPinToInterrupt(3), enter, RISING);
  attachInterrupt(digitalPinToInterrupt(18), stop_emergency, RISING);
  if ( !display.begin( SSD1306_SWITCHCAPVCC, 0x3C))  // when OLED not connect properly to the Mega , message fail will display
  {
    Serial.println(" Failed");

  }


  Wire.beginTransmission( mpuAddress);
  Wire.write( 0x6B);
  Wire.write( 0);
  auto error = Wire.endTransmission();
  if ( error != 0)
  {
    Serial.println( " MPU not found");   // when MPU not connect properly to the Mega , message fail appeared on serial

  }

  pinMode(VERT_PIN, INPUT);
  pinMode(HORZ_PIN, INPUT);
  pinMode(8, OUTPUT);// pin of buzzer
  pinMode(SEL_PIN, INPUT_PULLUP);

  ADCSRA =  bit (ADEN);                      // turn ADC on
  ADCSRA |= bit (ADPS0) |  bit (ADPS1) | bit (ADPS2);  // Prescaler of 128
  ADMUX  =  bit (REFS0) | (adcPin & 0x07);    // AVcc and select input port

  cli();




  //set time1
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 625;// = (16*10^6) / (100*256) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS10 bits for 256 prescaler
  TCCR1B |= (1 << CS12) ;
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);



  sei();//allow interrupts
}


// timer interrupt
ISR(TIMER1_COMPA_vect) {

  check_mpu = true ;
  if (activate_count == 1 ) {
    count_time_turnon = count_time_turnon + 1 ;

  }
  if (dataMessage == 1) {
    messageTime += 1;

  }

}


// ADC complete ISR
ISR (ADC_vect)
{
  adcReading = ADC;
  adcDone = true;
}  // end of ADC_vect



// button select and exit to menu interrupt 
void enter() {
  button_time_2 = millis();


  if (button_time_2 - lastbutton_time_2 > 50 && button_time_2 - lastbutton_time_2 < 400  ) {
    choose_user = 1;
    lastbutton_time_2 = button_time_2;


  }
  if (button_time_2 - lastbutton_time_2 > 400 &&  button_time_2 - lastbutton_time_2 < 2000 ) {

    lastbutton_time_2 = button_time_2;

  }
  if (button_time_2 - lastbutton_time_2 > 2000 ) {
    choose_user = 0 ;

    lastbutton_time_2 = button_time_2;

  }


  //Serial.print(option);

}

// interrupt for choose option button 
void next_step() {
  button_time_1 = millis();
  if (button_time_1 - lastbutton_time_1 > 200 ) {

    lastbutton_time_1 = button_time_1;

  }

  if (button_time_1 - lastbutton_time_1 > 50 && button_time_1 - lastbutton_time_1 < 200  ) {
    option = option + 1;
    lastbutton_time_1 = button_time_1;


  }

  if (option > 3 ) {
    option = 0 ;


  }

}

// stop the alert of fall detect button 
void stop_emergency ()
{

  button_time_3 = millis();

  if (button_time_3 - lastbutton_time_3 > 50 && button_time_3 - lastbutton_time_3 < 400  ) {
    activate_count = 0;
    button_3 = 1 ;
    lastbutton_time_3 = button_time_3;


  }

  if (button_time_3 - lastbutton_time_3 > 200 && button_time_3 - lastbutton_time_3 < 2000  ) {

    lastbutton_time_3 = button_time_3;

  }


  if (button_time_3 - lastbutton_time_3 > 2000 ) {

    button_3 = 0 ;
    lastbutton_time_3 = button_time_3;

  }





}


void loop()
{

  read_mpu_data();
  read_data_from_temp_sensor();
  
  
  if ( option  == 0 && choose_user == 0 ) {
    display.clearDisplay();
    display.setCursor(2, 5 );
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.println("Please Follow Option ");
    display.setCursor(20, 20 );
    display.println("1/Inital Position");
    display.setCursor(20, 35 );
    display.println("2/Body Temperature");
    display.setCursor(20, 50 );
    display.println("3/Fall Detect");
    display.display();
    recieve_menu_serial();
    attachInterrupt(digitalPinToInterrupt(2), next_step, RISING);
  }
  else if (option == 1 && choose_user == 0 )
  {
    display.clearDisplay();
    display.setCursor(2, 5 );
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.drawRoundRect(15, 18, 113, 13, 8, WHITE);
    display.println("Please Follow Option ");
    display.setCursor(20, 20 );
    display.println("1/Inital Position");
    display.setCursor(20, 35 );
    display.println("2/Body Temperature");
    display.setCursor(20, 50 );
    display.println("3/Fall Detect");
    display.display();
    
    recieve_menu_serial();
    attachInterrupt(digitalPinToInterrupt(2), next_step, RISING);
  }
  else if (option == 2 && choose_user == 0 ) {


    display.clearDisplay();
    display.setCursor(2, 5 );
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.drawRoundRect(15, 33, 113, 13, 8, WHITE);
    display.println("Please Follow Option ");
    display.setCursor(20, 20 );
    display.println("1/Inital Position");
    display.setCursor(20, 35 );
    display.println("2/Body Temperature");
    display.setCursor(20, 50 );
    display.println("3/Fall Detect");
    display.display();
    recieve_menu_serial();
    attachInterrupt(digitalPinToInterrupt(2), next_step, RISING);

  }
  else if (option == 3 && choose_user == 0 ) {

    display.clearDisplay();
    display.setCursor(2, 5 );
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.drawRoundRect(15, 47, 113, 13, 8, WHITE);
    display.println("Please Follow Option ");
    display.setCursor(20, 20 );
    display.println("1/Inital Position");
    display.setCursor(20, 35 );
    display.println("2/Body Temperature");
    display.setCursor(20, 50 );
    display.println("3/Fall Detect");
    display.display();


    recieve_menu_serial();
    attachInterrupt(digitalPinToInterrupt(2), next_step, RISING);


  }

  if (option == 1 && choose_user == 1 ) {

    if (dataMessage == 0) {
      readWritePosition();
      dataMessage = 1;

    }

    if (messageTime < 100) {
      dataMessage = 1;
      display.clearDisplay();
      display.setCursor(20, 30 );
      display.setTextColor(WHITE);
      display.setTextSize(1);
      display.println("Initial Postion ");
      display.setCursor(45, 40 );
      display.println("Saved");
      display.display();
    } else if (messageTime >= 100) {
      dataMessage = 0;
      messageTime = 0;
      choose_user = 0;
    }
    detachInterrupt(digitalPinToInterrupt(2));
    EIFR = 0b00000011;
  }

  else  if (option == 2 && choose_user == 1 ) {


    if (dataMessage == 0) {

      EEPROM.put(25, celsius);
      dataMessage = 1;

    }
    else if (messageTime >= 150 ) {
      dataMessage = 0;
      messageTime = 0;

    }

    EEPROM.get(25, temperatureValue);

  

    // if (messageTime < 150){
    display.clearDisplay();
    display.setCursor(2, 5 );
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.println("Human Temperature");
    display.setTextSize(2);
    display.setCursor(35, 25);
    display.drawCircle(107, 25, 2, WHITE);
    display.println(temperatureValue );
    display.setCursor(110, 25);
    display.println("C");

    if (celsius < 38 && celsius > 35 ) {
      display.drawCircle( 20, 45, 15, WHITE);
      display.fillCircle( 15, 45, 2, WHITE);
      display.fillCircle(28, 45, 2, WHITE);
      display.fillTriangle(15, 53, 25, 53, 25, 58, WHITE);
      display.setTextSize(1);
      display.setCursor(55, 45);
      display.println("Good");
      display.setCursor(45, 55);
      display.println("Temperature");
    }
    else if (celsius > 38 ) {
      display.drawCircle( 20, 45, 15, WHITE);
      display.fillCircle( 13, 45, 2, WHITE);
      display.fillCircle(28, 45, 2, WHITE);
      display.drawCircle( 20, 50, 5, WHITE);
      display.setTextSize(1);
      display.setCursor(55, 45);
      display.println("HOT");
      display.setCursor(45, 55);
      display.println("Temperature");
    }
    else {

      display.drawCircle( 20, 45, 15, WHITE);
      display.fillCircle( 13, 45, 2, WHITE);
      display.fillCircle(28, 45, 2, WHITE);
      display.drawCircle( 20, 50, 5, WHITE);
      display.setTextSize(1);
      display.setCursor(55, 45);
      display.println("Cold");
      display.setCursor(45, 55);
      display.println("Temperature");




    }
    display.display();


    detachInterrupt(digitalPinToInterrupt(2));

    EIFR = 0b00000011;

  }

  else  if (option == 3 && choose_user == 1 ) {
    fall_detect_display();
    detachInterrupt(digitalPinToInterrupt(2));
    EIFR = 0b00000011;
  }





}


void draw_wireframe(void)
{

  display.clearDisplay();

  // draw the pyramid shape  on the oled
  display.drawLine( wireframe[0][0], wireframe[0][1], wireframe[1][0], wireframe[1][1], SSD1306_WHITE);
  display.drawLine( wireframe[1][0], wireframe[1][1], wireframe[2][0], wireframe[2][1], SSD1306_WHITE);
  display.drawLine( wireframe[2][0], wireframe[2][1], wireframe[3][0], wireframe[3][1], SSD1306_WHITE);
  display.drawLine( wireframe[3][0], wireframe[3][1], wireframe[0][0], wireframe[0][1], SSD1306_WHITE);

  display.drawLine( wireframe[4][0], wireframe[4][1], wireframe[5][0], wireframe[5][1], SSD1306_WHITE);
  display.drawLine( wireframe[5][0], wireframe[5][1], wireframe[6][0], wireframe[6][1], SSD1306_WHITE);
  display.drawLine( wireframe[6][0], wireframe[6][1], wireframe[7][0], wireframe[7][1], SSD1306_WHITE);
  display.drawLine( wireframe[7][0], wireframe[7][1], wireframe[4][0], wireframe[4][1], SSD1306_WHITE);

  display.drawLine( wireframe[0][0], wireframe[0][1], wireframe[4][0], wireframe[4][1], SSD1306_WHITE);
  display.drawLine( wireframe[1][0], wireframe[1][1], wireframe[5][0], wireframe[5][1], SSD1306_WHITE);
  display.drawLine( wireframe[2][0], wireframe[2][1], wireframe[6][0], wireframe[6][1], SSD1306_WHITE);
  display.drawLine( wireframe[3][0], wireframe[3][1], wireframe[7][0], wireframe[7][1], SSD1306_WHITE);

  display.drawLine( wireframe[1][0], wireframe[1][1], wireframe[3][0], wireframe[3][1], SSD1306_WHITE);
  display.drawLine( wireframe[0][0], wireframe[0][1], wireframe[2][0], wireframe[2][1], SSD1306_WHITE);





  // draw the direction map on the OLED
  display.drawLine (115, 27, 95, 27, SSD1306_WHITE);
  display.drawLine (115, 27, 110, 25, SSD1306_WHITE);
  display.drawLine (115, 27, 110, 29, SSD1306_WHITE);
  display.drawLine (95, 10, 95, 27, SSD1306_WHITE);
  display.drawLine (95, 27, 105, 19, SSD1306_WHITE);
  display.drawLine (105, 19, 100, 19, SSD1306_WHITE);
  display.drawLine (105, 19, 105, 21, SSD1306_WHITE);
  display.drawLine (95, 10, 92, 15, SSD1306_WHITE);

  display.drawLine (95, 10, 98, 15, SSD1306_WHITE);

  display.setCursor(90, 0);
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.println("y ");
  display.setCursor(100, 10);
  display.println("z" );
  display.setCursor(115, 20);
  display.println("x");


  // display the accleration value and direction at the right bottom of the screen
  display.setCursor(60, 40);
  display.setTextColor(WHITE);
  display.setTextSize(0);
  display.println("x");
  display.setCursor(59, 50);
  display.println(xAccel_dis);
  display.setCursor(80, 40);
  display.println("y");
  display.setCursor(80, 50);
  display.println(yAccel_dis);
  display.setCursor(105, 40);
  display.println("z");
  display.setCursor(105, 50);
  display.println(zAccel_dis );
  display.display();
}


void read_mpu_data() {


  Wire.beginTransmission( mpuAddress);
  Wire.write( 0x3B);
  Wire.endTransmission( false);


  // read the input data of mpu in byte
  if (check_mpu == true ) {
    Wire.requestFrom( mpuAddress, 14);   // request a total of 14 bytes
    AcX = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
    AcY = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
    AcZ = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
    Temperature = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H)   & 0x42 (TEMP_OUT_L)
    GyX = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H)  & 0x44 (GYRO_XOUT_L)
    GyY = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H)  & 0x46 (GYRO_YOUT_L)
    GyZ = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H)  & 0x48 (GYRO_ZOUT_L)
  }

  check_mpu = false ;


  previous_Time = current_Time; // read old time
  current_Time = millis();  // read the current time of system
  interval_Time = (current_Time - previous_Time) / 1000; // calculate the time interval between old time and current
  // change it to second

  // calibrate the raw data from mpu and convert it to the actual accleration
  xByAccel =  AcX * 0.0001;
  yByAccel =  AcY * 0.0001;
  zByAccel =  AcZ * 0.0001;

  // calblirate the raw input of the gyro (rotation )
  xByGyro +=  GyX * 0.0001;
  yByGyro +=  GyY * 0.0001;
  zByGyro +=  GyZ * 0.0001;

  xAccel_cal = ( AcX / 16384.0) * 9.81;
  yAccel_cal = ( AcY / 16384.0) * 9.81;
  zAccel_cal = ( AcZ / 16384.0) * 9.81;
  xAccel_dis =  xAccel_cal;
  yAccel_dis =  yAccel_cal;
  zAccel_dis =  zAccel_cal;




  // calculate velocity of x y z base on the acceleration above
  new_velocityx = old_velocityx +  xAccel_cal * interval_Time;
  old_velocityx =  new_velocityx   ;

  new_velocityy = old_velocityy +  yAccel_cal * interval_Time;
  old_velocityy =  new_velocityy   ;

  new_velocityz = old_velocityz +  zAccel_cal * interval_Time;
  old_velocityz =  new_velocityz   ;

  double t = pow(interval_Time, 2);// calulate the t square

  // calculate the displacement in each axis
  displacement_xcurrent = (new_velocityx * interval_Time) + (1 / 2) * ((xAccel_cal) * t);
  displacement_ycurrent = (new_velocityy * interval_Time) + (1 / 2) * ((yAccel_cal) * t);
  displacement_zcurrent = (new_velocityz * interval_Time) + (1 / 2) * ((zAccel_cal) * t);


  x =   xByGyro;
  y =  yByGyro;
  z =  zByGyro;

  // keep the radian in the range of 0 to 2pi
  if ( x < 0.0)
    x = x + (2.0 * M_PI);
  else if ( x > 2.0 * M_PI)
    x = x - (2.0 * M_PI);
  if ( y < 0.0)
    y = y + (2.0 * M_PI);
  else if ( y > 2.0 * M_PI)
    y = y - ( 2.0 * M_PI);
  if ( z < 0.0)
    z = z +  (2.0 * M_PI);
  else if ( z > 2.0 * M_PI)
    z = z -  (2.0 * M_PI);



  calculate_fall ();



}

// calculate fall of human
void calculate_fall ()
{
  checkfall_xAccel  =  pow( xAccel_cal, 2);
  checkfall_yAccel  =  pow( yAccel_cal, 2);
  checkfall_zAccel  =  pow( zAccel_cal, 2);

  total_checkfall = checkfall_xAccel + checkfall_yAccel + checkfall_zAccel ;

  A_SVM = sqrt(total_checkfall);

  checkfall_roll = tan( x)  * tan( x);
  checkfall_pitch = tan( z) * tan ( z);
  total_checkfall_ptandroll = checkfall_roll + checkfall_pitch ;
  s_total_angle_fall = sqrt(total_checkfall_ptandroll);
  if (s_total_angle_fall == 0 ) {
    total_fall_angle = 0 ;



  }
  else {
    total_fall_angle =  atan(1 / ( s_total_angle_fall )) * (180 / M_PI);
  }

  //Serial.println(activate_count );

  if (total_fall_angle < 31 && A_SVM > 20 && total_fall_angle != 0 ) {

    if (button_3 == 0) {
      activate_count = 1 ;

      option = 3 ;
      choose_user = 1;

    }






  }


  if  (celsius > 38 || celsius < 35 ) {

    digitalWrite(12, HIGH);


  }
  else {

    digitalWrite(12, LOW);



  }

  if ( count_time_turnon > 300 ) {
    tone(8, 500, 1000); // in real life set the time above about 4 sec to get better notification
    count_time_turnon = 0 ;
  }








}




void fall_detect_display() {


  // the below function will responsible for rotation of x y and z
  for (int i = 0; i < NUM_VERTICES; i++)
  {
    // Rotate Y
    double  rotx_aroundy = triangle_vertex[i][2] * sin(y) + triangle_vertex[i][0] * cos(y);
    double  roty_aroundy = triangle_vertex[i][1];
    double  rotz_aroundy = triangle_vertex[i][2] * cos(y) - triangle_vertex[i][0] * sin(y);

    // Rotate X
    double  rotxx = rotx_aroundy;
    double  rotyy = roty_aroundy * cos(x) - rotz_aroundy * sin(x);
    double  rotzz = roty_aroundy * sin(x) + rotz_aroundy * cos(x);

    // Rotate Z
    double  rotxxx = rotxx * cos(z) - rotyy * sin(z);
    double  rotyyy = rotxx * sin(z) + rotyy * cos(z);
    double  rotzzz = rotzz;

    // Add depth perspective
    rotxxx *= viewDistance / (viewDistance + rotzzz);
    rotyyy *= viewDistance / (viewDistance + rotzzz);

    //  shift the pyramid along x axis
    if ( xByAccel > 0 ) {
      if (xOrigin < 50  ) // the pyramid will not move if it origin larger than 49
        xOrigin = xOrigin + 1; //move to the right

    }
    else if (xByAccel < 0 ) {
      if (xOrigin > 20   ) // the pyramid will not move if it origin smaller  than 21
        xOrigin = xOrigin - 1; // move left
    }
    else if  (xAccel_cal == 0 ) {   // the pyramid will be at the original point when no movement make

      xOrigin = 40;


    }

    //  shift the pyramid along y axis
    if ( yByAccel > 0 ) {
      if (yOrigin >= 20  )  // the pyramid will not move if it origin smaller  than 21
        yOrigin = yOrigin - 1 ; // move up

    }
    else if (yByAccel < 0 ) { // the pyramid will not move if it origin larger than 29
      if (yOrigin < 30   )
        yOrigin = yOrigin + 1; // move down
    }
    else if  (yAccel_cal == 0) {  // the pyramid will be at the original point when no movement make


      yOrigin = 25;

    }





    //  shift the pyramid along z axis
    if ( zByAccel > 0 ) {

      xOrigin = 50; // set the inward direction for z movement
      yOrigin = 22.5;
      if ( xByAccel > 0 ) {  // move to the right (when z also being set)
        if (xOrigin < 60  ) {
          xOrigin = xOrigin + 1;
        }

      }
      else if (xByAccel < 0 ) {  // move to the left (when z also being set)
        if (xOrigin > 10   )
          xOrigin = xOrigin - 1;
      }

      if ( yByAccel > 0 ) {   // move  up (when z also being set)
        if (yOrigin >= 20  )
          yOrigin = yOrigin - 1 ;

      }
      else if (yByAccel < 0 ) {  // move down  (when z also being set)
        if (yOrigin < 50   )
          yOrigin = yOrigin + 1;
      }


    }



    else if ( zByAccel < 0 ) {
      xOrigin = 23;  // set the inward direction for z movement
      yOrigin = 42.5;
      if ( xByAccel > 0 ) {
        if (xOrigin < 28 ) {
          xOrigin = xOrigin + 1;
        }
      }
      else if (xByAccel < 0 ) {
        if (xOrigin > 20   ) {
          xOrigin = xOrigin - 1;
        }
      }

      if ( yByAccel > 0 ) {
        if (yOrigin >= 20  )
          yOrigin = yOrigin - 1 ;

      }
      else if (yByAccel < 0 ) {
        if (yOrigin < 47   )
          yOrigin = yOrigin + 1;
      }






    }





    // Bring to middle of screen
    rotxxx = rotxxx + xOrigin;
    rotyyy = rotyyy + yOrigin;

    // Store new vertices values for wireframe drawing
    wireframe[i][0] = (int) rotxxx;
    wireframe[i][1] = (int) rotyyy;
    wireframe[i][2] = (int) rotzzz;
  }







  draw_wireframe();


}

//function for password protection
void checkPassword() {
  int flag = 0;
  String newAttempt = "";
  //read password length from EEPROM
  int length = EEPROM.read(0);
  char passwordCheck[length + 1] = "";

  //loop until correct password is input
  while (flag < 1) {

    while (Serial.available()) {
      //recieve password attempt from Serial monitor
      newAttempt = Serial.readString();
      //remove extra character from the end of the string for comparison
      newAttempt.remove(newAttempt.length() - 1);

      //loop to read saved password from EEPROM in to character array
      for (int i = 0; i < length; i++) {
        passwordCheck[i] = EEPROM.read(1 + i);

      }
      //add terminating character to string
      passwordCheck[length + 1] = '\0';

      //check if password attempt is correct or incorrect
      if (newAttempt != "") {
        if (newAttempt != String(passwordCheck)) {
          Serial.println("Error: Incorrect Password");



        } else if (newAttempt == String(passwordCheck)) {
          Serial.println("Password Accepted");
          flag = 1;
        }
      }
    }
  }
}


void readWritePosition() {
  //write x, y, z displacement
  writeToMemory(30, displacement_xcurrent); //write x displacement
  writeToMemory(32, displacement_ycurrent); //write y displacement
  writeToMemory(34, displacement_zcurrent); //write z displacement
  //print current position
  Serial.println();
  Serial.print("X Position: ");
  Serial.print(readFromMemory(30));
  Serial.println();
  Serial.print("Y Position: ");
  Serial.print(readFromMemory(32));
  Serial.println();
  Serial.print("Z Position: ");
  Serial.print(readFromMemory(34));
  Serial.println();

  //calculate x, y, z, rotation
  int xRotation = ((int)xByGyro - (((int)xByGyro / 360) * 360)) % 360;
  int yRotation = ((int)yByGyro - (((int)yByGyro / 360) * 360)) % 360;
  int zRotation = ((int)zByGyro - (((int)zByGyro / 360) * 360)) % 360;

  writeToMemory(36, xRotation); //write x rotation
  writeToMemory(38, yRotation); //write y rotation
  writeToMemory(40, zRotation); //write z rotation
  //print current rotation
  Serial.println();
  Serial.print("X Rotation: ");
  Serial.print(readFromMemory(36));
  Serial.println();
  Serial.print("Y Rotation: ");
  Serial.print(readFromMemory(38));
  Serial.println();
  Serial.print("Z Rotation: ");
  Serial.print(readFromMemory(40));
  Serial.println();


}



void writeToMemory(int address, int number) {
  byte firstByte = number >> 8; //take only higher 8 bytes
  byte secondByte = number & 0xFF; //take only lower 8 bytes

  EEPROM.write(address, firstByte); //write higher bytes to address
  EEPROM.write(address + 1, secondByte); //write lower bytes to next address


}

int readFromMemory(int address) {
  byte firstByte = EEPROM.read(address); //read first half from address
  byte secondByte = EEPROM.read(address + 1); //read second half from address

  return (firstByte << 8) + secondByte; //shift first half back to original position and add second half

}

void read_data_from_temp_sensor() {
  if (adcDone)
  {
    adcStarted = false;

    // get the adcRading to become temp value
    temp = adcReading;




    adcDone = false;
  }

  // if we aren't taking a reading, start a new one
  if (!adcStarted)
  {
    adcStarted = true;
    // begin to start the conversion
    ADCSRA |= bit (ADSC) | bit (ADIE);
  }


 // cablirate the raw temperature 
  celsius = 1 / (log(1 / (1023. / temp - 1)) / Beta + 1.0 / 298.15) - 273.15;


}


// recieve the data from input 
void recieve_menu_serial() {
  // check for any avaliable input
  while (Serial.available()) {
  
    // if yes read it as a char and combine to string 
    if (Serial.available() > 0) {
      char menu_option_raw = Serial.read();
      readString += menu_option_raw  ;
    }
  }

  if (readString.length() > 0) {
    Serial.println(readString);

    // take out the element of string which  hour is element 1 and 2 in the string 
     menu_option  = readString.substring(0, 1);
    Serial.print ("Your choosing option : ");
    Serial.println(menu_option);
  

   // change all the input second hour and minute from string to int 
    char num1[4];
    menu_option.toCharArray( num1, sizeof( num1));
    option= atoi(num1);

    readString = "";

  }



}