#include <SPI.h> //Библиотека для работу с MCP2515 по SPI
#include "mcp2515.h" //Библиотека с основными функциями для CAN модуля, CAN-A
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // Ширина OLED-дисплея, в пикселях
#define SCREEN_HEIGHT 64 // Высота OLED-дисплея, в пикселях
// Декларация для дисплея SSD1306, подключенного к I2C (контакты SDA, SCL)
#define OLED_RESET -1 // Сброс pin-кода # (или -1, если используется общий pin-код сброса Arduino)

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define DOORFL A0 //Дверь передняя левая
#define DOORFP A1 //Дверь передняя правая
#define DOORBL A2 //Дверь задняя левая
#define DOORBP A3 //Дверь задняя правая
#define BONNET 3 //Капот
#define TRUNK 4 //Багажник

uint32_t timer = 0;
uint32_t timer1 = 0;
uint32_t timer2 = 0;
uint32_t timer3 = 0;
uint32_t timer4 = 0;

bool StatusDOORFL = false;//Храним статусы открыл или  закрыт 0 закрыт 1 открыт
bool StatusDOORFP = false;//Храним статусы открыл или  закрыт 0 закрыт 1 открыт
bool StatusDOORBL = false;//Храним статусы открыл или  закрыт 0 закрыт 1 открыт
bool StatusDOORBP = false;//Храним статусы открыл или  закрыт 0 закрыт 1 открыт
bool StatusBONNET = false;//Храним статусы открыл или  закрыт 0 закрыт 1 открыт
bool StatusTRUNK = false;//Храним статусы открыл или  закрыт 0 закрыт 1 открыт

struct can_frame canMsg1; //Структура кадра
MCP2515 mcp2515(10); //Контакт выбора для работы модуля

int SPEED = 0; //Храним тут скорость
int TEMP = 64;  //Храним  Тут температуру типа двигателя
int PRM = 0;   //Храним тут обороты
uint32_t TRIP = random(70000, 120000);
int mili = 0;

void setup() {//Вы полнится один раз
  pinMode(DOORFL, INPUT_PULLUP);
  pinMode(DOORFP, INPUT_PULLUP);
  pinMode(DOORBL, INPUT_PULLUP);
  pinMode(DOORBP, INPUT_PULLUP);
  pinMode(BONNET, INPUT_PULLUP);
  pinMode(TRUNK, INPUT_PULLUP);
  while (!Serial); //Проверка запуска сириал 
  Serial.begin(115200); //Иницилизация сериала  
  mcp2515.reset(); // сброс настроек MCP2515 так надо, чтобы лучше работал!
  mcp2515.setBitrate(CAN_250KBPS,MCP_8MHZ); //Настройка основных параметров скорости и частота кристала на плате, это важно!!!
  mcp2515.setNormalMode(); //иницилизация и запуск  
  Serial.println("Example: Write to CAN");
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("SSD1306 allocation failed");
  }
  display.clearDisplay(); // Чистим буфер
  display.setCursor(14, 12);
  display.setTextColor(WHITE);
  display.setTextSize(2);
  display.println("START OK!");
  display.display();
}
  /*
  canMsg1.can_id  = random(1, 100);
  canMsg1.can_dlc = 8; // Задаем размер кадра
  canMsg1.data[0] = random(0, 255);
  canMsg1.data[1] = random(0, 255);
  canMsg1.data[2] = random(0, 255);
  canMsg1.data[3] = random(0, 255);
  canMsg1.data[4] = random(0, 255);
  canMsg1.data[5] = random(0, 255);
  canMsg1.data[6] = random(0, 255);
  canMsg1.data[7] = random(0, 255);
  mcp2515.sendMessage(&canMsg1); //Отправляем сообщение в CAN шину
  */

void loop() {//выполняется постоянно
  if(millis() - timer >= 1000){
    timer = millis();
    Imidgedata();
  }

  if(millis() - timer1 >= 100){
    timer1 = millis();
    SendStatusDoors(); //Формируем кан сообщения и отправляем статусы
    SendTemp();
    SendRandom1();
    trip();
  }

  if(millis() - timer2 >= 50){
    timer2 = millis();
    SetStatusDoors();//Получаем значение открыты или закрыты  двери
  }

  if(millis() - timer3 >= 50){
    timer3 = millis();
    SendSpeed();
    SendRandom2();
  }

  if(millis() - timer4 >= 75){
    timer4 = millis();
    SenPRM();
    SendRandom();
  }
}

void SetStatusDoors(){//Считываем статусы
  StatusDOORFL = digitalRead(DOORFL);
  StatusDOORFP = digitalRead(DOORFP);
  StatusDOORBL = digitalRead(DOORBL);
  StatusDOORBP = digitalRead(DOORBP);
  StatusBONNET = digitalRead(BONNET);
  StatusTRUNK = digitalRead(TRUNK);
}

void SendStatusDoors(){
  uint8_t PinDoors = 0x00;
  if(StatusDOORFL){
    bitSet(PinDoors, 0);
  }
  if(StatusDOORFP){
    bitSet(PinDoors, 1);
  }
  if(StatusDOORBL){
    bitSet(PinDoors, 2);
  }
  if(StatusDOORBP){
    bitSet(PinDoors, 3);
  }
  if(StatusBONNET){
    bitSet(PinDoors, 7);
  }
  if(StatusTRUNK){
    bitSet(PinDoors, 6);
  }

  canMsg1.can_id  = 0x65;
  canMsg1.can_dlc = 8; // Задаем размер кадра
  canMsg1.data[0] = PinDoors;
  canMsg1.data[1] = StatusDOORFL;
  canMsg1.data[2] = StatusDOORFP;
  canMsg1.data[3] = StatusDOORBL;
  canMsg1.data[4] = StatusDOORBP;
  canMsg1.data[5] = StatusBONNET;
  canMsg1.data[6] = StatusTRUNK;
  canMsg1.data[7] = 0x00;
  mcp2515.sendMessage(&canMsg1);
  //Serial.println(PinDoors, BIN);
}

void Imidgedata(){
  int temp_speed = random(0, 10);
  int temp_snak = random(0, 10);
  //Serial.println(temp_snak);
  if(temp_snak > 3){
    SPEED = SPEED + temp_speed;
  }
  else{
    SPEED = SPEED - temp_speed;
  }
  if(SPEED > 120){
    SPEED = 120;
  }
  if(SPEED < 0){
    SPEED = 0;
  }
  PRM = random(600, 800);
  PRM = PRM + SPEED*10;

  TEMP = TEMP + 1;
  if(TEMP > 150){
    TEMP = 150;
  }

  mili = mili + SPEED;
  if(mili >=1000){
    TRIP++;
    mili = mili - 1000;
  }
  Serial.println(mili);

  display.clearDisplay(); // Чистим буфер
  display.setCursor(0, 0);
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.print("SPEED ");
  display.println(SPEED);
  display.setCursor(0, 10);
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.print("PRM ");
  display.println(PRM);
  display.setCursor(0, 20);
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.print("TEMP ");
  display.println(TEMP-40);
  display.setCursor(0, 30);
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.print("TRIP ");
  display.println(TRIP);
  display.display();
}

void SendSpeed(){
  canMsg1.can_id  = 0x55;
  canMsg1.can_dlc = 4; // Задаем размер кадра
  canMsg1.data[0] = SPEED;
  canMsg1.data[1] = 0x00;
  canMsg1.data[2] = SPEED/10;
  canMsg1.data[3] = SPEED - canMsg1.data[2]*10;
  mcp2515.sendMessage(&canMsg1);
}

void SendTemp(){
  canMsg1.can_id  = 0x56;
  canMsg1.can_dlc = 8; // Задаем размер кадра
  canMsg1.data[0] = 0x255;
  canMsg1.data[1] = SPEED;
  canMsg1.data[2] = 0x255;
  canMsg1.data[3] = TEMP;
  canMsg1.data[4] = 0x255;
  canMsg1.data[5] = random(0, 255);
  canMsg1.data[6] = 0x255;
  canMsg1.data[7] = 0x255;
  mcp2515.sendMessage(&canMsg1);
}

void SenPRM(){
  canMsg1.can_id  = 0x45;
  canMsg1.can_dlc = 8; // Задаем размер кадра
  canMsg1.data[0] = random(0, 255);
  canMsg1.data[1] = random(0, 255);
  canMsg1.data[2] = PRM >> 8;
  canMsg1.data[3] = PRM;
  canMsg1.data[4] = 0x00;
  canMsg1.data[5] = 0x00;
  canMsg1.data[6] = 0x00;
  canMsg1.data[7] = 0x00;
  mcp2515.sendMessage(&canMsg1);
}

void SendRandom(){
  canMsg1.can_id  = random(46, 54);
  canMsg1.can_dlc = random(1, 8); // Задаем размер кадра
  canMsg1.data[0] = random(0, 255);
  canMsg1.data[1] = random(0, 255);
  canMsg1.data[2] = random(0, 255);
  canMsg1.data[3] = random(0, 255);
  canMsg1.data[4] = random(0, 255);
  canMsg1.data[5] = random(0, 255);
  canMsg1.data[6] = random(0, 255);
  canMsg1.data[7] = random(0, 255);
  mcp2515.sendMessage(&canMsg1);
}

void SendRandom1(){
  canMsg1.can_id  = random(57, 64);
  canMsg1.can_dlc = random(1, 8); // Задаем размер кадра
  canMsg1.data[0] = random(0, 255);
  canMsg1.data[1] = random(0, 255);
  canMsg1.data[2] = random(0, 255);
  canMsg1.data[3] = random(0, 255);
  canMsg1.data[4] = random(0, 255);
  canMsg1.data[5] = random(0, 255);
  canMsg1.data[6] = random(0, 255);
  canMsg1.data[7] = random(0, 255);
  mcp2515.sendMessage(&canMsg1);
}

void SendRandom2(){
  canMsg1.can_id  = random(67, 100);
  canMsg1.can_dlc = random(1, 8); // Задаем размер кадра
  canMsg1.data[0] = random(0, 255);
  canMsg1.data[1] = random(0, 255);
  canMsg1.data[2] = random(0, 255);
  canMsg1.data[3] = random(0, 255);
  canMsg1.data[4] = random(0, 255);
  canMsg1.data[5] = random(0, 255);
  canMsg1.data[6] = random(0, 255);
  canMsg1.data[7] = random(0, 255);
  mcp2515.sendMessage(&canMsg1);
}

void trip(){
  canMsg1.can_id  = 0x66;
  canMsg1.can_dlc = 8; // Задаем размер кадра
  canMsg1.data[0] = (TRIP >> 24) & 0xFF;
  canMsg1.data[1] = (TRIP >> 16) & 0xFF;
  canMsg1.data[2] = (TRIP >> 8) & 0xFF;
  canMsg1.data[3] = TRIP & 0xFF;
  canMsg1.data[4] = 0x00;
  canMsg1.data[5] = 0x00;
  canMsg1.data[6] = SPEED;
  canMsg1.data[7] = 0x00;
  mcp2515.sendMessage(&canMsg1);
}