#include "LiquidCrystal_I2C.h"
#include <Wire.h> // Include the Wire library for I2C communication

#define I2C_ADDR    0x27
#define LCD_COLUMNS 20
#define LCD_LINES   4
#define ENCODER_A PA0
#define ENCODER_B PA1
#define ONE_WIRE_BUS 2 // Define the pin for OneWire
#define SKIP_ROM 0xCC // Command code for DS18B20
#define CONVERT_T 0x44 // Command code for DS18B20
#define READ_SCRATCHPAD 0xBE // Command code for DS18B20
#define MPU6050_ADDRESS 0x68 // I2C address for MPU6050

LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);

volatile int encoderPosition = 0;
volatile int lastEncoded = 0;
int lastDisplayState = -1;

void setup() {
  Serial.begin(115200);
  lcd.init();
  lcd.backlight();
  displayScene(encoderPosition % 3);

  pinMode(ENCODER_A, INPUT_PULLUP);
  pinMode(ENCODER_B, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(ENCODER_A), updateEncoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ENCODER_B), updateEncoder, CHANGE);
}

void loop() {
  int currentScene = encoderPosition % 3;
  if (currentScene != lastDisplayState) {
    displayScene(currentScene);
    lastDisplayState = currentScene;
  }
}

void displayScene(int sceneIndex) {
  int temperatureC; // Declare variable before switch
  lcd.clear();
  switch (sceneIndex) {
    case 0:
      displayAccelerometerData();
      break;
    case 1:
      temperatureC = readTemperature();
      Serial.println("Temp: ");
      Serial.println(temperatureC / 100); // Integer part
      Serial.println('.');
      Serial.println(temperatureC % 100); // Decimal part
      Serial.println(" C");
      break;
    case 2:
      Serial.println("Scene 3");
      break;
  }
}

void displayAccelerometerData() {
  int16_t ax, ay, az;
  readMPU6050(&ax, &ay, &az, NULL, NULL, NULL);
  lcd.setCursor(0, 0);
  Serial.println("Accel X: ");
  Serial.println(ax);
  Serial.println(0, 1);
  Serial.println("Accel Y: ");
  Serial.println(ay);
  Serial.println(0, 2);
  Serial.println("Accel Z: ");
  Serial.println(az);
}

void updateEncoder() {
  int MSB = digitalRead(ENCODER_A); // Read the most significant bit (MSB)
  int LSB = digitalRead(ENCODER_B); // Read the least significant bit (LSB)
  int encoded = (MSB << 1) | LSB;  // Convert the 2 bit number to single integer
  int sum = (lastEncoded << 2) | encoded;

  if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderPosition++;
  if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderPosition--;

  lastEncoded = encoded; // Store current encoded value as last encoded for next call
}

void writeOneWire(uint8_t data) {
  for (uint8_t i = 0; i < 8; i++) {
    if (data & 0x01) {
      pinMode(ONE_WIRE_BUS, OUTPUT);
      digitalWrite(ONE_WIRE_BUS, LOW);
      delayMicroseconds(10);
      pinMode(ONE_WIRE_BUS, INPUT);
      delayMicroseconds(55);
    } else {
      pinMode(ONE_WIRE_BUS, OUTPUT);
      digitalWrite(ONE_WIRE_BUS, LOW);
      delayMicroseconds(65);
      pinMode(ONE_WIRE_BUS, INPUT);
      delayMicroseconds(5);
    }
    data >>= 1;
  }
}

uint8_t readOneWire() {
  uint8_t result = 0;
  for (uint8_t i = 0; i < 8; i++) {
    pinMode(ONE_WIRE_BUS, OUTPUT);
    digitalWrite(ONE_WIRE_BUS, LOW);
    delayMicroseconds(3);
    pinMode(ONE_WIRE_BUS, INPUT);
    delayMicroseconds(10);
    if (digitalRead(ONE_WIRE_BUS)) {
      result |= (1 << i);
    }
    delayMicroseconds(53);
  }
  return result;
}

void resetOneWire() {
  pinMode(ONE_WIRE_BUS, OUTPUT);
  digitalWrite(ONE_WIRE_BUS, LOW);
  delayMicroseconds(480);
  pinMode(ONE_WIRE_BUS, INPUT);
  delayMicroseconds(70);
  delayMicroseconds(410);
}
int readTemperature() {
  resetOneWire();
  writeOneWire(SKIP_ROM);
  writeOneWire(CONVERT_T);
  delay(750); // Время для конверсии температуры

  resetOneWire();
  writeOneWire(SKIP_ROM);
  writeOneWire(READ_SCRATCHPAD);

  uint8_t lsb = readOneWire();
  uint8_t msb = readOneWire();
  int16_t temp = (msb << 8) | lsb;

  return (temp * 625) / 100; // Возвращаем температуру в целых и дробных частях
}

void readMPU6050(int16_t* ax, int16_t* ay, int16_t* az, int16_t* gx, int16_t* gy, int16_t* gz) {
  Wire.beginTransmission(MPU6050_ADDRESS);
  Wire.write(0x3B); // Начать чтение с регистра акселерометра
  Wire.endTransmission(false);
  Wire.requestFrom(MPU6050_ADDRESS, 14, true);

  if (ax) *ax = (Wire.read() << 8) | Wire.read();
  if (ay) *ay = (Wire.read() << 8) | Wire.read();
  if (az) *az = (Wire.read() << 8) | Wire.read();
  Wire.read(); Wire.read(); // Пропускаем температуру
  if (gx) *gx = (Wire.read() << 8) | Wire.read();
  if (gy) *gy = (Wire.read() << 8) | Wire.read();
  if (gz) *gz = (Wire.read() << 8) | Wire.read();
}