#include <packets2021.h>
#include <Adafruit_NeoPixel.h>
#include <LedControlcustomized.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <DigitLedDisplay.h>

// WiFi credentials
#define WIFI_SSID "omiderfani"
#define WIFI_PASS "******"

// Network settings
#define UDP_PORT 20777
#define MAX_PACKET_SIZE 2048

// NeoPixel settings
#define  PIN      D4
#define NUMPIXELS 24


// Colors
#define COLOR_RED   0xFF0000
#define COLOR_GREEN 0x00FF00
#define COLOR_BLUE  0x0000FF
 <br class="avia-permanent-lb"> <br class="avia-permanent-lb">
uint32_t revLightColors[3] = {COLOR_GREEN, COLOR_RED, COLOR_BLUE};

// Set your Static IP address
IPAddress local_IP(192, 168, 1, 5);
// Set your Gateway IP address
IPAddress gateway(192, 168, 1, 1);

IPAddress subnet(255, 255, 255, 0);
//IPAddress primaryDNS(8, 8, 8, 8);   //optional
//IPAddress secondaryDNS(8, 8, 4, 4); //optional

WiFiUDP UDP;
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
LedControl lc = LedControl(D0, D2, D1, 1); //DATA IN,CLK,CS
// Digit 7 segment
DigitLedDisplay ld = DigitLedDisplay(D6, D7, D8); //DIN, CS, CLK
byte packet[MAX_PACKET_SIZE];

byte matrix_map[13][8] =
{
  {0x00, 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6},       // R
  {0xFF, 0x3C, 0x0C, 0x24, 0x30, 0x38, 0x3C, 0x3C},       // N
  {0x00, 0x18, 0x18, 0x38, 0x18, 0x18, 0x18, 0x7E},       // 1
  {0x00, 0x3C, 0x66, 0x06, 0x0C, 0x30, 0x60, 0x7E},       // 2
  {0x00, 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C},       // 3
  {0x00, 0x0C, 0x1C, 0x2C, 0x4C, 0x7E, 0x0C, 0x0C},       // 4
  {0x00, 0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C},       // 5
  {0x00, 0x3C, 0x66, 0x60, 0x7C, 0x66, 0x66, 0x3C},       // 6
  {0x00, 0x7E, 0x66, 0x0C, 0x0C, 0x18, 0x18, 0x18},       // 7
  {0x00, 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C},       // 8
  {0xFF, 0x03, 0x99, 0x99, 0x83, 0x9F, 0x9F, 0x0F},       // P
  {0xFB, 0xF3, 0xC3, 0xF3, 0xF3, 0xF3, 0xC1, 0xC1},       // F1
  {0x04, 0x0C, 0x3C, 0x0C, 0x0C, 0x0C, 0x3E, 0x3E}        // F2
};


typedef enum {
  MOTION,
  SESSION,
  LAP,
  EVENT,
  PARTICIPANTS,
  SETUPS,
  TELEMETRY,
  CARSTATUS,
  FINALCLASS,
  LOBBYINFO,
  CARDAMAGE,
  History
} packet_type_t;


float glat = 0; // Longitudinal G-Force component
int gear = 0;
int drs = 0;
int rev = 0;
int revb = 0;
int spd = 0;
int ETEM = 0; //Engine temperature (celsius)
int drsAllowed = 0;
int RPM = 0;
int fuelmix = 0;
int pit = 0;
int tyre = 0;
int ersm = 0;
int flag = 0;
int tyretrr = 0;
int tyretrl = 0;
int tyretfr = 0;
int tyretfl = 0;
int temp = 0;
float wtyrewrr = 0;//Rear Right (RR)Tyre wear=1
float wtyrewrl = 0;//Rear Left (RL)Tyre wear-0
float wtyrewfr = 0; //front Left (FL)Tyre wear-4
float wtyrewfl = 0; //front Right (FL)Tyre wear-3
int wtyrerr = 0;  // Tyre damage (percentage)
int wtyrerl = 0;
int wtyrefl = 0;
int wtyrefr = 0;
int DRSX = 0;
int tyretype = 0;
float MGUK = 0;
float MGUH = 0;
float DERS = 0;
float erse = 0;
int DRSF = 0;


volatile uint8_t blink_state = 0;
uint8_t blink_r = 0;
uint8_t blink_g = 0;
uint8_t blink_b = 0;

void ICACHE_RAM_ATTR timerISR() {
  switch (blink_state) {
    case 0:
      blink_state = 1;
      timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);
      timer1_write(5000000); // 1 second
      break;
    case 1:
      blink_state = 2;
      timer1_write(5000000); // 1 second
      break;
    case 2:
      timer1_disable();
      blink_state = 0;
      break;
    default:
      break;
  }
}

void Blink(uint8_t r, uint8_t g, uint8_t b) {
  if (blink_state == 0) {
    blink_r = r;
    blink_g = g;
    blink_b = b;
    timerISR();
  }
}
 <br class="avia-permanent-lb">

void printByte(byte character [])
{
  int i = 0;
  for (i = 0; i < 8; i++)
  {
    lc.setRow(0, i, character[i]);
  }
}


void setup() {
  pixels.setBrightness(15);
  ld.setBright(6);
  lc.setIntensity(0, 4);
  ld.setDigitLimit(8);   //DigitLedDisplay
  lc.shutdown(0, false);      //The MAX72XX

  lc.clearDisplay(0);
  // Setup serial port
  Serial.begin(115200);
  //  Serial.println();

  // Configures static IP address
  if (!WiFi.config(local_IP, gateway, subnet)) {
    Serial.println("STA Failed to configure");
  }

  // Begin WiFi
  WiFi.begin(WIFI_SSID, WIFI_PASS);

  // Connecting to WiFi...
//  Serial.print("Connecting to ");
//  Serial.print(WIFI_SSID);
  // Loop continuously while WiFi is not connected
  while (WiFi.status() != WL_CONNECTED)
  { printByte(matrix_map[11]);
    delay(100);

    printByte(matrix_map[12]);

  }

  ld.write(3, B01100011);
  delay(200);
  ld.write(4, B00011101);
  delay(50);

  UDP.begin(UDP_PORT);

ld.printDigit(2021,2);
 
delay(0);
  pixels.clear();
  timer1_attachInterrupt(timerISR); // Add ISR Function
}

void loop() {
  // If packet received...
  int packetSize = UDP.parsePacket();
  struct NetworkPacket * networkPacket;
  struct PacketMotionData * packetMotionData;
  struct CarMotionData * motionData;
  struct CarTelemetryData telemetryData;
  struct CarStatusData statusData;
  struct CarDamageData dmgData;

  if (packetSize) {
   
    int len = UDP.read(packet, MAX_PACKET_SIZE);

    if (len)
    {
      networkPacket = (NetworkPacket *)packet;
      int playerIndex = networkPacket->header.m_playerCarIndex;
      switch (networkPacket->header.m_packetId)

      {
        case MOTION:
//          packetMotionData = (PacketMotionData *)networkPacket;
//          motionData = &((PacketMotionData *)networkPacket)->m_carMotionData[playerIndex];
//          glat = motionData->m_gForceLongitudinal;
          break;
        case SESSION:
          break;
        case LAP:
          break;
        case EVENT:
          break;
        case PARTICIPANTS:
          break;
        case SETUPS:
          break;
        case TELEMETRY:
          telemetryData = ((PacketCarTelemetryData *)networkPacket)->m_carTelemetryData[playerIndex];

          tyretrr = telemetryData.m_tyresInnerTemperature[1];
          tyretrl = telemetryData.m_tyresInnerTemperature[0];
          tyretfr = telemetryData.m_tyresInnerTemperature[3];
          tyretfl = telemetryData.m_tyresInnerTemperature[2];
          temp = telemetryData.m_engineTemperature;
          drs = telemetryData.m_drs;
          spd = telemetryData.m_speed;
          RPM = telemetryData.m_engineRPM;
          gear = telemetryData.m_gear;
          rev = telemetryData.m_revLightsPercent;
//          revb = telemetryData.m_revLightsBitValue;
          

          break;
        case CARSTATUS:
          statusData = ((PacketCarStatusData *)networkPacket)->m_carStatusData[playerIndex];
          drsAllowed = statusData.m_drsAllowed;
          fuelmix = statusData.m_fuelMix;
          flag = statusData.m_vehicleFiaFlags;  //FIA Flags
          ersm = statusData.m_ersDeployMode;
          pit = statusData.m_pitLimiterStatus;
//          tyre = statusData.m_actualTyreCompound; //TyreCompound- C type
         
          erse = statusData.m_ersStoreEnergy;
          DRSX = statusData.m_drsActivationDistance;
       
          break;
        case FINALCLASS:
          break;
        case LOBBYINFO:
          break;
         case CARDAMAGE:
         dmgData = ((PacketCarDamageData *)networkPacket)->m_carDamageData[playerIndex];
         wtyrerr = dmgData.m_tyresDamage[1];
          wtyrerl = dmgData.m_tyresDamage[0];
          wtyrefr = dmgData.m_tyresDamage[3];
          wtyrefl = dmgData.m_tyresDamage[2];

          DRSF = dmgData.m_drsFault; 
          break;
//case History:
//          break;
      }


      pixels.clear();

      ld.clear();
      ld.printDigit(RPM, -1);
      ld.printDigit(spd, 5);
      //Tyre 
      if (tyretfl>=110){
        pixels.setPixelColor((21), 255, 0, 0);
        ld.write(5, B00011101);
      } else if (tyretfl<79){
        pixels.setPixelColor((21), 0, 0, 255-tyretfl);
        }
      else{
         pixels.setPixelColor((21), 0, tyretfl, 0);
      }
      
      if (tyretrl>=110){
        pixels.setPixelColor((22), 255, 0, 0);
        ld.write(5, B00011101);
      }else if (tyretrl<79){
        pixels.setPixelColor((22), 0, 0, 255-tyretrl);
        }
      else{
         pixels.setPixelColor((22), 0, tyretrl, 0);
      }
      
      if (tyretfr>=110){
        pixels.setPixelColor((18), 255, 0, 0);
        ld.write(5, B00011101);
      }else if (tyretfr<79){
        pixels.setPixelColor((18), 0, 0, 255-tyretfr);
        }
      else
     {
       pixels.setPixelColor((18), 0, tyretfr, 0);
     }
     
      if (tyretrr>=110){
        pixels.setPixelColor((17), 255, 0, 0);
        ld.write(5, B00011101);
      
      }else if (tyretrr<79){
        pixels.setPixelColor((17), 0, 0, 255-tyretrr);
        }
      else
     {
       pixels.setPixelColor((17), 0, tyretrr, 0);
     }

      //Engine temperature 
      if (temp>=120){
      pixels.setPixelColor((19), temp,0, 0);
      }
 
      // flag
      if (flag == 0) {
        pixels.setPixelColor((23), 0, 0, 0);
        pixels.setPixelColor((16), 0, 0, 0);
      }
      else if (flag == 1) {
        Blink(  0, 255, 10);
      }
      else if (flag == 2) {
        Blink( 0, 0, 255);
      }
      else if (flag == 3) {
        Blink( 250, 170, 0);
      }
      else if (flag == 4) {

        Blink ( 255, 0, 0);
      }

      if (blink_state == 1) {
        pixels.setPixelColor (16, blink_r, blink_g, blink_b);
      } else if (blink_state == 2) {
        pixels.setPixelColor (23, blink_r, blink_g, blink_b);
      }

// Slip indicator each wheel

       if (DRSF == 1){
       ld.write(5, B00000100);
      }

        if (DRSX> 0){
        ld.write(5, B01000000);
       }

if (fuelmix== 0){
        ld.write(5, B10000001);
       }


      //PIT Limiter
      if (pit == 1) {

        printByte(matrix_map[10]);
      } else {
        // Display Gear
        printByte(matrix_map[gear + 1]);
      }



      // Display ERS
      if (ersm == 0) {

        pixels.setPixelColor((20), 0, 0, 0);
      }
      else if (ersm == 1) {

        pixels.setPixelColor((20), 100, 50, 50);
      }
      else if (ersm == 2) {
       
        pixels.setPixelColor((20), 255, 0, 255);
      }
      else if (ersm == 3) {
       
        pixels.setPixelColor((20), 0, 255, 0);
        pixels.setPixelColor((19), 0, 255, 0);
      }
      

      // Display DRS
      
      if (drsAllowed == 0) {
        if (drs == 0) {

          pixels.setPixelColor((0), 0, 0, 55);

        }
        else if (drs == 1) {

          pixels.setPixelColor((0), 255, 0, 255);
          pixels.setPixelColor((1), 255, 0, 255);
          lc.setRow(0, 0, B10100101);

        }
      }

      else if (drsAllowed == 1) {
        if (drs == 0) {
          lc.setRow(0, 0, B10000001);
          pixels.setPixelColor((0), 100, 255, 0);

        }
      }

      // Display RevLight
      int n = rev / 7;
      int color;
      for (int i = 1; i < n + 1; ++i) {
        color = revLightColors[(i - 1) / 5];
        pixels.setPixelColor(i, color);
      }
      if (rev == 100) {
        pixels.fill(COLOR_BLUE, 1, 15);
      }
      


 
 pixels.begin();
      pixels.show(); delay(0);


    
  } } }