#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <HardwareSerial.h>
#include <U8glib-HAL.h>
#include <string>
#include <iostream>
#include <utility>
#include <vector>
#include <Fonts/Brolocatoricons.h>
#include <WiFi.h>
#include <esp_now.h>
#include <esp_wifi.h>  
#include <driver/i2s.h>

// V3.4.2 Voice Updated

// PIN LOCATIONS
#define OLED_RESET 4
#define ENCODER_CLK 18
#define ENCODER_DT 19
#define ENCODER_SW 15
#define SWL 5
#define SWR 4
#define LORA_TX 16
#define LORA_RX 17
#define LORA_WAIT 14 // AUX Pin
//Mic
#define I2S_MIC_PORT      I2S_NUM_0
#define I2S_WS 25
#define I2S_SD 32
#define I2S_SCK 33
//Speaker
#define I2S_SPK_PORT      I2S_NUM_1
#define I2S_BCLK 26
#define I2S_LRC 27
#define I2S_DIN 23

// VALUES AND SETTINGS
bool debug_mode = false;
bool Force_Fails = false;
bool alt_Enc_decoder = false;
int debounce = 200;

SemaphoreHandle_t Message_Var_Semaphore;
SemaphoreHandle_t Avail_To_Send_Semaphore;
SemaphoreHandle_t ESP_NOW_Ack_Semaphore;
SemaphoreHandle_t ESP_NOW_Rcv_Semaphore;
TaskHandle_t Main_UI_Task_Handle = NULL;
TaskHandle_t Voice_Task_Handle = NULL;
TaskHandle_t Wireless_Task_Handle = NULL;

unsigned long LoRa_Time_Between_Retry = 1000;
unsigned long LoRa_Time_Between_Pings = 490;
unsigned long Alert_Auto_Dismiss = 3000;
unsigned LoRa_Pings_Sent = 0;
int LoRa_Pings_Recieved = 0;
int Lora_Allowed_Attempts = 9;
bool LoRa_Pingdicator = false;
char LoRa_Indicator = '0';

esp_now_peer_info_t ESP_NOW_PEER;
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
String peer_mac_addr;
bool ESP_NOW_Peer_Ack = false;
bool ESP_NOW_Peer_Locked_in = false;
bool ESP_NOW_Rcv = true;
int ESP_NOW_Channel = 0;
int ESP_NOW_RSSI = 0;
int lastRSSI = 0;
String ESPnow_Strength = "???dBm";
#define SAMPLE_RATE 16000
#define BUFFER_LEN 128  // small chunks
int16_t i2sBuffer[BUFFER_LEN];

int Current_Mode = 0;
String Current_Mode_Name[] = {"Init", "Home", "Message Composer","Voice","Simple"};
String All_Messages[100];
int All_Messages_Counter = 0;

// Home Values
int Home_Counter = 0;
int Home_Countertotal = 2;

// MESSAGE COMPOSE VALUES
bool Msg_Compose_Fn_Init = true;
int lastStateENCODER_CLK = HIGH;
int currentStateENCODER_CLK;
int Msg_Compose_Counter = 0;
int Msg_Max_Length = 63;
int Msg_Compose_Countertotal = 39; // Length of Character array (Set to 0 for auto config)
int lastStateMsg_Compose_Counter;
String Msg_Compose_Message = "";
volatile bool Avaliable_For_Send_Message = false;
String LastStateOfMsg_Compose_Message;
char StuffsArray[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '?', '!', '.', ' '};

// Voice menu values
bool Voice_Setup_flag = true;

//|-------------------------------------------------------------------------------------------------------------------------|
//|                                                                                                                         |
//|                                            * F U N C T I O N  D E F *                                                   |
//|                                                                                                                         |
//|-------------------------------------------------------------------------------------------------------------------------|

// PRE-INIT STUFF
Adafruit_SSD1306 display(OLED_RESET);
Adafruit_SSD1306 display2(OLED_RESET);
HardwareSerial LoRaSerial(2);

// IO Fn Decleration
int Encoder_Direction_Readout(); // 0 = CCW, 1 = CW, 2 = No Change
bool Encoder_Switch();           // True = Pressed, False = Not Pressed
bool Switch_Swl();               // True = Pressed, False = Not Pressed
bool Switch_Swr();               // True = Pressed, False = Not Pressed

// System IO Tracker Declerations
void Encoder_Event_Tracker();
void Encoder_Button_Event_Tracker();
void SwR_Event_Tracker();
void SwL_Event_Tracker();

//Wireless
// S$ Send Code
// A$ Ack Send Code
// P$ Ping (heartbeat) Code

void LoRa_Message_Sender();
void Wireless_Link_State();
void Status_Bar_Updater(bool Change, bool Change2, bool LoRa_True, bool ESPNOW_True, int RSSI);

// ESP NOW Fn Def (Thanks ChatGPT)

// Promiscuous RX callback — captures packet metadata, including RSSI whatever tf this means but it works
void wifi_sniffer_packet_handler(void *buff, wifi_promiscuous_pkt_type_t type) {
  wifi_promiscuous_pkt_t *pkt = (wifi_promiscuous_pkt_t *)buff;
  lastRSSI = pkt->rx_ctrl.rssi;
}

void onSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  if (Current_Mode != 3) {
    Serial.printf("ESPNOW_CORE - Packet sent to: %02X:%02X:%02X:%02X:%02X:%02X | Status: %s\n",
                mac_addr[0], mac_addr[1], mac_addr[2],
                mac_addr[3], mac_addr[4], mac_addr[5],
                (status == ESP_NOW_SEND_SUCCESS) ? "Success" : "Fail");
  }
}

void onReceive(const uint8_t *mac_addr, const uint8_t *IncomingData, int len) {

  if (*IncomingData != 0)
  {
    xSemaphoreTake(ESP_NOW_Rcv_Semaphore, 10);
    ESP_NOW_Rcv = true;
    xSemaphoreGive(ESP_NOW_Rcv_Semaphore);
    size_t bytesWritten;
    i2s_write(I2S_SPK_PORT, IncomingData, len, &bytesWritten, portMAX_DELAY);
  }
  else {
    // Print received heartbeat
    Serial.printf("\nESPNOW_CORE - [From %02X:%02X:%02X:%02X:%02X:%02X]\n",
                  mac_addr[0], mac_addr[1], mac_addr[2],
                  mac_addr[3], mac_addr[4], mac_addr[5]);

    Serial.println("ESPNOW_CORE -  Incoming Code: " + String(*IncomingData));
    // Check if peer already added and adds it if its not
    xSemaphoreTake(ESP_NOW_Ack_Semaphore, 50);
    ESP_NOW_Peer_Ack = true;
    xSemaphoreGive(ESP_NOW_Ack_Semaphore);
    Status_Bar_Updater(false,true,false,true,lastRSSI);
  }
}

void playStartupTone() {
  const int freq = 200; // 1 kHz tone
  const int durationMs = 10; // tone duration
  const int sampleRate = 16000;

  int samples = (sampleRate * durationMs) / 1000;
  int16_t buffer[256];
  float phase = 0;
  float phaseIncrement = 2.0f * M_PI * freq / sampleRate;

  unsigned long start = millis();
  while (millis() - start < durationMs) {
    for (int i = 0; i < 256; i++) {
      buffer[i] = (int16_t)(sin(phase) * 32767);
      phase += phaseIncrement;
      if (phase >= 2.0f * M_PI) phase -= 2.0f * M_PI;
    }
    size_t bytesWritten;
    i2s_write(I2S_SPK_PORT, buffer, sizeof(buffer), &bytesWritten, portMAX_DELAY);
  }
  static int16_t silenceBuf[256] = {0};
  size_t written;
  for (int i = 0; i < 10; i++) {
    i2s_write(I2S_SPK_PORT, silenceBuf, sizeof(silenceBuf), &written, portMAX_DELAY);
  }
}

// General System Fn Declerations

void Alert_displayer(String Message_Top, String Message_Bottom);
void Alert_Recover();

String cleanString(String input) {
  String output = "";
  for (unsigned int i = 0; i < input.length(); i++) {
    char c = input[i];
    // Keep only printable ASCII characters (space to ~)
    if (c >= 32 && c <= 126) {
      output += c;
    }
  }
  return output;
}

//Msg Composer Fn Decleration
void Msg_Compose_Counter_Updater(int direction); // Update the Msg Counter variable to keep within msg counter val (Takes in direction from Encoder_Direction_Readout())
void Msg_Compose_Display_Renderer(); // Updates screen to show Message Composer Stuff
void Msg_Compose(int State, int Encoder_Direction_Value); // Main Message Compose Function

// Home functions
void Home_items_Selector(int State, int Encoder_Direction_Value);
void Home_Display_Renderer();

// Voice functions

void Voice_Main();


// FREERTOS STUFFS
void Main_UI_Loop(void *parameters)
{
  Serial.println("System State - Main UI Loop Process Started");
  for (;;)
  {
    Encoder_Event_Tracker();
    Encoder_Button_Event_Tracker();
    SwR_Event_Tracker();
    SwL_Event_Tracker();
    vTaskDelay(1 / portTICK_PERIOD_MS);
  }
}

void Voice_Loop(void *parameters)
{
  Serial.println("System State - Voice Loop Process Started");
  for (;;)
  {
    Voice_Main();
  }
}

void Wireless_Loop(void *parameters)
{
  Serial.println("System State - Wireless Loop Process Started");
  for (;;)
  {
    Wireless_Link_State();
  }
}

void Simple_mode_Loop(void *parameters)
{
  Serial.println("System State - Simple Mode Process Started");
  int counter = 0;
  vTaskSuspend(Main_UI_Task_Handle);
  vTaskSuspend(Wireless_Task_Handle);
  eTaskState state1 = eTaskGetState(Main_UI_Task_Handle);
  eTaskState state2 = eTaskGetState(Wireless_Task_Handle);
  Serial.println((int)state1);
  Serial.println((int)state2);
  display2.clearDisplay();
  display2.setFont(NULL);
  display2.setTextSize(1);
  display2.setTextColor(WHITE);
  display2.setCursor(0, 12);
  display2.println("Prim Mode");
  display.setCursor(0, 24);
  display2.println("Rst To Exit");
  display2.display();
  LoRaSerial.flush();
  for (;;)
  {
    bool iran = false;
    if (LoRaSerial.available())
    {
      String incoming = LoRaSerial.readStringUntil('\n');
      if (incoming.indexOf("P$") >= 0) {
        incoming = "Peer Not\nIn Prim sending\n Prim Request";
        LoRaSerial.println("J$");
        while (LoRaSerial.available())
        {
          LoRaSerial.read();
        }
      }
      display.clearDisplay();
      display.setTextSize(1);
      display.setTextColor(WHITE);
      display.setCursor(0, 8);
      display.println("Receieved: " + incoming);
      iran = true;
    }
    if (!iran) {
      display.clearDisplay();
    }
    delay(20);
    counter++;
    LoRaSerial.println(String(counter));
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 0);
    display.println("Sending: " + String(counter));
    display.display();
    delay(2000);
  }
}

struct Coords
{
  int x;
  int y;
};
struct Coords Bottom_Bar_First;
struct Coords Bottom_Bar_Second;
struct Coords Bottom_Bar_Third;

struct Coords Center_Bar_First;
struct Coords Center_Bar_Second;
struct Coords Center_Bar_Third;

//|-------------------------------------------------------------------------------------------------------------------------|
//|                                                                                                                         |
//|                                                  * S E T  U P *                                                         |
//|                                                                                                                         |
//|-------------------------------------------------------------------------------------------------------------------------|

// SETUP
void setup()
{
  Serial.begin(115200);
  Serial.println("   ----- INIT MODE -----   ");
  // Pin setup
  pinMode(ENCODER_CLK, INPUT);
  pinMode(ENCODER_DT, INPUT);
  pinMode(ENCODER_SW, INPUT_PULLUP);
  pinMode(SWL, INPUT_PULLUP);
  pinMode(SWR, INPUT_PULLUP);

  // Display INIT stuffs
  Serial.println("Starting Screen Stuffs...\n");

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display2.begin(SSD1306_SWITCHCAPVCC, 0x3D);

  if (Force_Fails) { // Acknowledgement screen (so that I know not to freak out when something does not work)
    display2.clearDisplay();
    display.clearDisplay();
    display.display();
    display2.display();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(25, 12);
    display.println("FORCE Fail");
    display.display();
    display2.clearDisplay();
    display2.setTextSize(1);
    display2.fillRect(0, 21, 128, 9, WHITE);
    display2.setTextColor(BLACK);
    display2.setCursor(12, 22);
    display2.println("Press Enc to Cont");
    display2.setTextColor(WHITE);
    display2.setCursor(25, 12);
    display2.println("Is Enabled");
    display2.display();

    bool DisplayAccept = false;
    while (!DisplayAccept) // Dismiss the screen stuff
    {
      if (Encoder_Switch()) {
        DisplayAccept = true;
      }
    }

    delay(200); // Delay for the button press to not affect next screen
    Serial.println("Force Fail Acknowledge\n");
  }
  if (debug_mode) {
    display2.clearDisplay();
    display.clearDisplay();
    display.display();
    display2.display();
    display.setTextSize(1);
    display.fillRect(0, 0, 128, 9, WHITE);
    display.setTextColor(BLACK);
    display.setCursor(10, 1);
    display.println("Debug Mode Enabled");
    display.setTextColor(WHITE);
    display.setCursor(25, 12);
    display.println("DISPLAY 0x3C");
    display.setCursor(0, 24);
    display.setFont(&Brolocatoricons);
    display.println("AMB210CD N");
    display.display();
    display2.clearDisplay();
    display2.setTextSize(1);
    display2.fillRect(0, 21, 128, 9, WHITE);
    display2.setTextColor(BLACK);
    display2.setCursor(12, 22);
    display2.println("Press Enc to Cont");
    display2.setTextColor(WHITE);
    display2.setCursor(25, 12);
    display2.println("DISPLAY2 0x3D");
    display2.setCursor(0, 1);
    display2.setFont(&Brolocatoricons);
    display2.println("EFGHIJKL");
    display2.display();

    bool DisplayAccept = false;
    while (!DisplayAccept) // Dismiss the screen stuff
    {
      if (Encoder_Switch()) {
        DisplayAccept = true;
      }
    }

    delay(200); // Delay for the button press to not affect next screen
    Serial.println("Done Screen Stuffs...\n");
  }

  //Display element coordinates INIT

  Bottom_Bar_First.x = 16;
  Bottom_Bar_First.y = 32;
  Bottom_Bar_Second.x = 59;
  Bottom_Bar_Second.y = 32;
  Bottom_Bar_Third.x = 97;
  Bottom_Bar_Third.y = 32;

  Center_Bar_First.x = 15;
  Center_Bar_First.y = 28;
  Center_Bar_Second.x = 53;
  Center_Bar_Second.y = 28;
  Center_Bar_Third.x = 93;
  Center_Bar_Third.y = 28;

  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(2);
  display.setFont(&Brolocatoricons);
  display.setCursor(54, 24);
  display.println("N");
  display.setFont(NULL);
  display.display();
  display2.clearDisplay();
  display2.setTextColor(WHITE);
  display2.setTextSize(1);
  display2.setFont(NULL);
  display2.setCursor(41, 12);
  display2.println("Starting");
  display2.display();

  //  Debug
  Serial.println(Current_Mode_Name[Current_Mode] + " - [INIT] Pin setup:\n" + 
  "ENCODER_CLK - " + ENCODER_CLK + "\n"
  "ENCODER_DT - " + ENCODER_DT + "\n"
  "ENCODER_SW - " + ENCODER_SW + "\n"
  "SWL - " + SWL + "\n"
  "SWR - " + SWR + "\n");

  // LORA INIT stuffs
  LoRaSerial.begin(9600, SERIAL_8N1, LORA_TX, LORA_RX);
  Serial.println("LORA enabled");

  //  ESP NOW INIT Stuffs

  WiFi.mode(WIFI_STA); // Starts ESPNOW in Station Mode

  esp_wifi_set_promiscuous(true);
  esp_wifi_set_promiscuous_rx_cb(&wifi_sniffer_packet_handler);

  if (esp_now_init() != ESP_OK || Force_Fails) { // Starts and Checks if ESP NOW started correctly
    Serial.println("Error initializing ESP-NOW");
    display2.clearDisplay();
    display2.setTextColor(WHITE);
    display2.setTextSize(1);
    display2.setFont(NULL);
    display2.setCursor(0, 0);
    display2.print("ESPNOW Fail Start\n\nPress to Cont");
    display2.display();
    bool DisplayAccept = false;
    while (!DisplayAccept) // Dismiss the screen stuff
    {
      if (Encoder_Switch() || Switch_Swl() || Switch_Swr()) {
        DisplayAccept = true;
      }
    }
    display2.clearDisplay();
    display2.setCursor(41, 12);
    display2.println("Starting");
    display2.display();
  }

  if (esp_now_register_send_cb(onSent) != ESP_OK || Force_Fails) {
    Serial.println("Error registering esp_now send callback");
    display2.clearDisplay();
    display2.setTextColor(WHITE);
    display2.setTextSize(1);
    display2.setFont(NULL);
    display2.setCursor(0, 0);
    display2.print("ESPNOW Fail cb\n\nPress to Cont");
    display2.display();
    bool DisplayAccept = false;
    while (!DisplayAccept) // Dismiss the screen stuff
    {
      if (Encoder_Switch() || Switch_Swl() || Switch_Swr()) {
        DisplayAccept = true;
      }
    }
    display2.clearDisplay();
    display2.setCursor(41, 12);
    display2.println("Starting");
    display2.display();
  }

  if (esp_now_register_recv_cb(onReceive) != ESP_OK || Force_Fails) {
    Serial.println("Error registering esp_now send callback");
    display2.clearDisplay();
    display2.setTextColor(WHITE);
    display2.setTextSize(1);
    display2.setFont(NULL);
    display2.setCursor(0, 0);
    display2.print("ESPNOW Fail cb\n\nPress to Cont");
    display2.display();
    bool DisplayAccept = false;
    while (!DisplayAccept) // Dismiss the screen stuff
    {
      if (Encoder_Switch() || Switch_Swl() || Switch_Swr()) {
        DisplayAccept = true;
      }
    }
    display2.clearDisplay();
    display2.setCursor(41, 12);
    display2.println("Starting");
    display2.display();
  }
  memcpy(ESP_NOW_PEER.peer_addr, broadcastAddress, 6);
  ESP_NOW_PEER.channel = ESP_NOW_Channel;
  ESP_NOW_PEER.encrypt = false;

  if (esp_now_add_peer(&ESP_NOW_PEER) != ESP_OK || Force_Fails) {
    Serial.println("Error Adding Peer ESP-NOW");
    display2.clearDisplay();
    display2.setTextColor(WHITE);
    display2.setTextSize(1);
    display2.setFont(NULL);
    display2.setCursor(0, 0);
    display2.print("ESPNOW Fail Peer\n\nPress to Cont");
    display2.display();
    bool DisplayAccept = false;
    while (!DisplayAccept) // Dismiss the screen stuff
    {
      if (Encoder_Switch() || Switch_Swl() || Switch_Swr()) {
        DisplayAccept = true;
      }
    }
    display2.clearDisplay();
    display2.setCursor(41, 12);
    display2.println("Starting");
    display2.display();
  }

  if (esp_now_init() != ESP_OK || Force_Fails) { // Starts and Checks if ESP NOW started correctly
    Serial.println("Error initializing ESP-NOW");
    display2.clearDisplay();
    display2.setTextColor(WHITE);
    display2.setTextSize(1);
    display2.setFont(NULL);
    display2.setCursor(0, 0);
    display2.print("ESPNOW Fail Start\n\nPress to Cont");
    display2.display();
    bool DisplayAccept = false;
    while (!DisplayAccept) // Dismiss the screen stuff
    {
      if (Encoder_Switch() || Switch_Swl() || Switch_Swr()) {
        DisplayAccept = true;
      }
    }
    display2.clearDisplay();
    display2.setCursor(41, 12);
    display2.println("Starting");
    display2.display();
  }

  // I2S Setup Stuff (I have absolutely no clue whats going on Thanks ChatGPT)
  // Mic
  i2s_config_t MicConfig = {
      .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
      .sample_rate = SAMPLE_RATE,
      .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
      .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
      .communication_format = I2S_COMM_FORMAT_STAND_I2S,
      .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
      .dma_buf_count = 4,
      .dma_buf_len = 64,
      .use_apll = false,
  };

  i2s_pin_config_t MicPins = {
    .bck_io_num = I2S_SCK,
    .ws_io_num = I2S_WS,
    .data_out_num = I2S_PIN_NO_CHANGE,
    .data_in_num = I2S_SD
  };

  i2s_driver_install(I2S_MIC_PORT, &MicConfig, 0, NULL);
  i2s_set_pin(I2S_MIC_PORT, &MicPins);

  //Speaker
  i2s_config_t SpkConfig = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
    .sample_rate = SAMPLE_RATE,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = I2S_COMM_FORMAT_STAND_I2S,
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 4,
    .dma_buf_len = 64,
    .use_apll = false,
  };

  i2s_pin_config_t SpkPins = {
    .bck_io_num = I2S_BCLK,
    .ws_io_num = I2S_LRC,
    .data_out_num = I2S_DIN,
    .data_in_num = -1
  };

  i2s_driver_install(I2S_SPK_PORT, &SpkConfig, 0, NULL);
  i2s_set_pin(I2S_SPK_PORT, &SpkPins);

  Message_Var_Semaphore = xSemaphoreCreateMutex();
  Avail_To_Send_Semaphore = xSemaphoreCreateMutex();
  ESP_NOW_Ack_Semaphore = xSemaphoreCreateMutex();
  ESP_NOW_Rcv_Semaphore = xSemaphoreCreateMutex();

  delay(1000);

  Current_Mode = 1;
  Serial.println("   ----- HOME MODE -----   ");
  Home_Display_Renderer();


  //FREERTOS TASK CREATION
  xTaskCreatePinnedToCore(
    Main_UI_Loop,
    "Main_UI_Loop",
    10000,
    NULL,
    2,
    &Main_UI_Task_Handle,
    1
  );
  xTaskCreatePinnedToCore(
    Wireless_Loop,
    "Wireless_Loop",
    10000,
    NULL,
    2,
    &Wireless_Task_Handle,
    0
  );
}

void loop() {

}

// System IO Fns
int Encoder_Direction_Readout(){
  if (alt_Enc_decoder) {
    static unsigned long lastDebounceTime = 0;
    const unsigned long debounceDelay = 2; // 2 ms debounce

    int currentStateENCODER_CLK = digitalRead(ENCODER_CLK);

    // Only act on rising edge (LOW → HIGH)
    if (lastStateENCODER_CLK == LOW && currentStateENCODER_CLK == HIGH) {
      // Simple debounce to ignore chatter
      if (millis() - lastDebounceTime > debounceDelay) {
        lastDebounceTime = millis();

        if (digitalRead(ENCODER_DT) == HIGH) {
          Serial.println("SystemIO - [ENCODER CW> ROTATION] Value 1");
          lastStateENCODER_CLK = currentStateENCODER_CLK;
          return 0; // CCW
        } else {
          Serial.println("SystemIO - [ENCODER CCW< ROTATION] Value 0");
          lastStateENCODER_CLK = currentStateENCODER_CLK;
          return 1; // CW
        }
      }
    }

    lastStateENCODER_CLK = currentStateENCODER_CLK;
    return 2; // Idle
  }
  else {
    currentStateENCODER_CLK = digitalRead(ENCODER_CLK);
    if (currentStateENCODER_CLK != lastStateENCODER_CLK) {
      if (digitalRead(ENCODER_DT) != currentStateENCODER_CLK) {
        
        Serial.print("SystemIO - [ENCODER CW> ROTATION] Value 1\n");
        lastStateENCODER_CLK = currentStateENCODER_CLK;
        return 1; // Returns 1 if Encoder is rotated in CW> Direction
      } 
      else {
        Serial.print("SystemIO - [ENCODER CCW< ROTATION] Value 0\n");
        lastStateENCODER_CLK = currentStateENCODER_CLK;
        return 0; // Returns 0 if Encoder is rotated in CCW< Direction
      }
    }
    else {
      lastStateENCODER_CLK = currentStateENCODER_CLK;
      return 2; // Returns 2 if Encoder is idle but function is called
    }
  }
}

bool Encoder_Switch() {
  if (digitalRead(ENCODER_SW) == LOW) {
    Serial.print("SystemIO - [ENCODER PRESSED]\n");
    return true;
  }
  else {
    return false;
  }
}

bool Switch_Swl() {
  if (digitalRead(SWL) == LOW) {

    Serial.print("SystemIO - [SWL PRESSED]\n");
    return true;
  }
  else {
    return false;
  }
}

bool Switch_Swr() {
  if (digitalRead(SWR) == LOW) {
    Serial.print("SystemIO - [SWR PRESSED]\n");
    return true;
  }
  else {
    return false;
  }
}

void Encoder_Event_Tracker() {
  int Encoder_Direction_Common = Encoder_Direction_Readout();
  if (Encoder_Direction_Common != 2) {
    if (Current_Mode == 2) {
      Msg_Compose(0,Encoder_Direction_Common);
    }
    else if (Current_Mode == 1) {
      Home_items_Selector(0, Encoder_Direction_Common);
    }
  }
}

void Encoder_Button_Event_Tracker() {
  if (Encoder_Switch()) {
    if (Current_Mode == 2) {
      Msg_Compose(1, 0);
    }
    else if (Current_Mode == 1) {
      Home_items_Selector(1, 0);
    }
    vTaskDelay(debounce / portTICK_PERIOD_MS);
  }
}

void SwR_Event_Tracker() {
  if (Switch_Swr()) {
    if (Current_Mode == 2) {
      Msg_Compose(3, 0);
    }
    vTaskDelay(debounce / portTICK_PERIOD_MS);
  }
}

void SwL_Event_Tracker() {
  if (Switch_Swl()) {
    if (Current_Mode == 2) {
      Msg_Compose(2, 0);
    }
    vTaskDelay(debounce / portTICK_PERIOD_MS);
  }
}

void Alert_displayer(String Message_Top, String Message_Bottom) {
  display.clearDisplay();
  display.drawRect(4, 4, 120, 25, WHITE);
  display.fillRect(54, 0, 18, 12, BLACK);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(20, 12);
  display.setFont(NULL);
  display.println(Message_Top);
  display.setCursor(58, 3);
  display.setFont(&Brolocatoricons);
  display.println("N");
  display.setFont(NULL);
  display.display();

  display2.clearDisplay();
  display2.setTextSize(1);
  display2.setTextColor(WHITE);
  display2.setCursor(0, 0);
  display2.setFont(NULL);
  display2.println(Message_Bottom);
  display2.display();
  vTaskDelay(debounce / portTICK_PERIOD_MS);
  bool DisplayAccept = false;
  while (!DisplayAccept) {
    if (Encoder_Switch() || Switch_Swl() || Switch_Swr() || Encoder_Direction_Readout() != 2) {
      DisplayAccept = true;
    }
    if (LoRaSerial.available()) {
      String incoming = cleanString(LoRaSerial.readStringUntil('\n'));
      incoming.trim();
      Serial.println("Alert Display - LORA Avaliable Raw: " + incoming);
      if (incoming.indexOf("P$") >= 0) {
        vTaskDelay(50 / portTICK_PERIOD_MS);
        LoRaSerial.println("P$");
      }
      if (incoming.indexOf("S$") >= 0) {
        if (debug_mode)
        {
          Serial.println("Alert Display - LORA Message Recieved <-(S$)");
        }
        vTaskDelay(50 / portTICK_PERIOD_MS);
        LoRaSerial.println("A$");
        if (debug_mode)
        {
          Serial.println("Alert Display - LORA ReReplying With: A$");
        }
      }
    }
    vTaskDelay(10 / portTICK_PERIOD_MS);
  }
  Alert_Recover();
}

void Alert_Recover() {
  if (Current_Mode == 2) {
    Msg_Compose_Fn_Init = true;
    Msg_Compose_Display_Renderer();
  }
  else if (Current_Mode == 1) {
    Home_Display_Renderer();
  }
}

void LoRa_Message_Sender() {
  Serial.println("\n   ----- LoRa Message Sender Started -----   ");
  xSemaphoreTake(Message_Var_Semaphore, portMAX_DELAY);
  if (Main_UI_Task_Handle != NULL) {
    vTaskSuspend(Main_UI_Task_Handle);
  }

  //Init Variables
  String Message = "S$" + Msg_Compose_Message; // Adds Send code to message to send
  String ExpectedReply = "A$";                 // Creates Ack message to check against
  Serial.print(Current_Mode_Name[Current_Mode] + " - LORA Message Created: " + Message + "\n");
  Serial.print(Current_Mode_Name[Current_Mode] + " - LORA Reply Verification Created: " + ExpectedReply + "\n");
  bool Confirmed = false;

  xSemaphoreGive(Message_Var_Semaphore);

  // Loops throught Lora_Allowed_Attempts to attempt message send
  for (int i = 0; i < Lora_Allowed_Attempts && !Confirmed; i++) {

    // Send Message
    LoRaSerial.println(Message);
    Serial.print(Current_Mode_Name[Current_Mode] + " - LORA Message Attempting To Send...\n");
    vTaskDelay(50 / portTICK_PERIOD_MS);

    //Capture time
    unsigned long StartTime = millis();
    Serial.print(Current_Mode_Name[Current_Mode] + " - LORA Start Time estab: " + String(StartTime) + " - LORA Attempt: " + String(i+1) + "\n");

    //Update Screen with info
    display.clearDisplay();
    display.drawRect(4, 4, 120, 25, WHITE);
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(20, 12);
    display.println("Message Sending");
    display.display();
    display2.clearDisplay();
    display2.setTextSize(1);
    display2.setTextColor(WHITE);
    display2.setCursor(39, 2);
    display2.println("Attempt:");
    display2.setTextSize(2);
    display2.setCursor(54, 14);
    display2.println(String(i+1));
    display2.display();

    // Continously checks for Ack from Reciever (checks for reply for LoRa_Time_Between_Retry ammounts of time before resending message)
    while (millis() - StartTime < LoRa_Time_Between_Retry && !Confirmed) {
      String incoming;

      // Waits for when Ack is recieved
      if (LoRaSerial.available() > 0)
      {
        // Cleans incoming Ack removing any non ASCII characters (Thanks ChatGPT)
        incoming = cleanString(LoRaSerial.readStringUntil('\n'));
        incoming.trim();
        Serial.print(Current_Mode_Name[Current_Mode] + " - LORA Incoming(Shld be Ack A$): " + incoming + "\n");
        Serial.println(Current_Mode_Name[Current_Mode] + " - LORA Reply Index Value: " + String(incoming.indexOf(ExpectedReply)));

        // Checks if the Ack recieved contains ExpextedReply
        if (incoming.indexOf(ExpectedReply) >= 0)
        {
          Serial.print(Current_Mode_Name[Current_Mode] + " - LORA Ack Accepted");
          Confirmed = true;
        }
      }
    } 
  }

  if (!Confirmed || Force_Fails) {
  // Notify User if message is not deliverd ()
  display2.clearDisplay();
  display2.setTextSize(1);
  display2.setTextColor(WHITE);
  display2.setCursor(21, 12);
  display2.println("Attempt FAILED");
  display2.fillRect(0, 21, 128, 9, WHITE);
  display2.setTextColor(BLACK);
  display2.setCursor(12, 22);
  display2.println("Press Enc to Exit");
  display2.display();
  bool DisplayAccept = false;
  delay(200);

  while (!DisplayAccept)
  {
    if (Encoder_Switch()) {
      DisplayAccept = true;
    }
    if (LoRaSerial.available())
    {
      String incoming = cleanString(LoRaSerial.readStringUntil('\n'));
      incoming.trim();
      Serial.println("WiLink State - LORA Avaliable Raw: " + incoming);
      if (incoming.indexOf("P$") >= 0) {
        LoRaSerial.println("P$");
      }
    }
    vTaskDelay(10 / portTICK_PERIOD_MS);
  }
  vTaskDelay(debounce / portTICK_PERIOD_MS);
  Msg_Compose_Fn_Init = true;
  }
  else {
    display2.clearDisplay();
    display2.setTextSize(1);
    display2.setTextColor(WHITE);
    display2.setCursor(51, 2);
    display2.println("SENT");
    display2.setFont(&Brolocatoricons);
    display2.setCursor(52, 30);
    display2.setTextSize(2);
    display2.println("K");
    display2.setFont(NULL);
    display2.display();
    delay(500);
    Msg_Compose_Fn_Init = true;
  }
  Alert_Recover();
  if (Main_UI_Task_Handle != NULL) {
    vTaskResume(Main_UI_Task_Handle);
  }
  Serial.println("\n   ----- LoRa Message Sender Ended -----   ");
}

void Wireless_Link_State() {
  if (debug_mode) {
    Serial.println("\n   ----- Wireless Link Ping Started -----   ");
  }
  uint8_t ESP_NOW_SEND_CODE = 0;
  Serial.println("WiLink State - ESP NOW Code Set:" + String(ESP_NOW_SEND_CODE));
  if (esp_now_send(ESP_NOW_PEER.peer_addr, &ESP_NOW_SEND_CODE, sizeof(ESP_NOW_SEND_CODE)) != ESP_OK)
  {
    Serial.println("WiLink State - ESP NOW Failed to send idle code to peer (DISCONNECTED)");
  }
  Serial.println("WiLink State - Shutting Spkr up now");
  xSemaphoreTake(ESP_NOW_Rcv_Semaphore, portMAX_DELAY);
  bool shouldsilence = ESP_NOW_Rcv;
  xSemaphoreGive(ESP_NOW_Rcv_Semaphore);
  if (!shouldsilence) {
    // Send zeros to speaker buffer to silence it
    static int16_t silenceBuf[256] = {0};
    size_t written;
    for (int i = 0; i < 10; i++) {
      i2s_write(I2S_SPK_PORT, silenceBuf, sizeof(silenceBuf), &written, portMAX_DELAY);
    }
  }
  else {
    xSemaphoreGive(ESP_NOW_Rcv_Semaphore);
  }
  xSemaphoreTake(ESP_NOW_Rcv_Semaphore, portMAX_DELAY);
  ESP_NOW_Rcv = false; // Sets Rcv to false (if is rcv it will get changed back to true before silencer runs)
  xSemaphoreGive(ESP_NOW_Rcv_Semaphore);
  xSemaphoreTake(ESP_NOW_Ack_Semaphore, portMAX_DELAY);
  ESP_NOW_Peer_Ack = false; // setups ack to be acked or however uw to phrase it
  xSemaphoreGive(ESP_NOW_Ack_Semaphore);
  bool LoRa_Ping_Ack = false; // setups ack to be acked or however uw to phrase it
  vTaskDelay(50 / portTICK_PERIOD_MS);
  LoRaSerial.println("P$"); // Send Ping code
  Serial.println("WiLink State - Ping Sent ->(P$)");
  LoRa_Pings_Sent++;

  // Acting on recieved msg
  vTaskDelay(LoRa_Time_Between_Pings / portTICK_PERIOD_MS);
  String incoming;
  xSemaphoreTake(Avail_To_Send_Semaphore, portMAX_DELAY);
  if (Avaliable_For_Send_Message) {
    // Starts the message sender when it is requested
    Serial.println("WiLink State - LORA Picked Up Send Request");
    LoRa_Message_Sender();
    Avaliable_For_Send_Message = false;
  }
  xSemaphoreGive(Avail_To_Send_Semaphore);
  if (LoRaSerial.available())
  {
    // Cleans incoming Ack removing any non ASCII characters (Thanks ChatGPT)
    incoming = cleanString(LoRaSerial.readStringUntil('\n'));
    incoming.trim();
    Serial.println("WiLink State - LORA Avaliable Raw: " + incoming);

    // Checks For New Messages
    if (incoming.indexOf("S$") >= 0)
    {
      if (debug_mode)
      {
        Serial.println("WiLink State - LORA Message Recieved <-(S$)");
      }
      vTaskDelay(50 / portTICK_PERIOD_MS);
      LoRaSerial.println("A$");
      if (debug_mode)
      {
        Serial.println("WiLink State - LORA Replying With: A$");
      }
      All_Messages[All_Messages_Counter] = incoming.substring(2, incoming.length());
      if (debug_mode) 
      {
        Serial.println("WiLink State - All Message Added:" + All_Messages[All_Messages_Counter] + " | Counter: " + String(All_Messages_Counter));
      }
      All_Messages_Counter++;
      Alert_displayer("Message Recieved", incoming.substring(2, incoming.length()));
    }

    // Checks For Incoming Pings and replies
    if (incoming.indexOf("P$") >= 0)
    {
      if (debug_mode) {
        Serial.println("WiLink State - LORA Heart Beat Recieved");
      }
      Status_Bar_Updater(true,false,true,false,0);
      LoRa_Ping_Ack = true;
      LoRa_Pings_Recieved++;
    }

        // Checks For Prim mode Requests
    if (incoming.indexOf("J$") >= 0)
    {
      if (debug_mode) {
        Serial.println("WiLink State - LORA Converting Prim");
      }
      Current_Mode = 4;
      Serial.println("   ----- Prim MODE -----   ");
      xTaskCreatePinnedToCore(
          Simple_mode_Loop,
          "Simple_mode_Loop",
          20000,
          NULL,
          1,
          NULL,
          0);
    }
  }

  if (!LoRa_Ping_Ack) {
    Status_Bar_Updater(true,false,false,false,0);
    Serial.println("WiLink State - LORA Peer No Heart Beat");
  }
  xSemaphoreTake(ESP_NOW_Ack_Semaphore, portMAX_DELAY);
  if (!ESP_NOW_Peer_Ack)
  {
    xSemaphoreGive(ESP_NOW_Ack_Semaphore);
    Status_Bar_Updater(false,true,false,false,0);
    Serial.println("WiLink State - ESP NOW peer disconnected");
  }
  else {
    xSemaphoreGive(ESP_NOW_Ack_Semaphore);
  }
  
  if (debug_mode)
  {
    Serial.println("\n   ----- Wireless Link Ping Ended -----   ");
  }
}

void Status_Bar_Updater(bool Change, bool Change2, bool LoRa_True, bool ESPNOW_True, int RSSI) {
  String ESP_NOW_ICONVAL;
  if (Current_Mode == 1)
  {
    display.fillRect(0, 0, 128, 8, BLACK);
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 0);
    display.setFont(&Brolocatoricons);
    if (!LoRa_Pingdicator && Change) {
      if (LoRa_True)
      {
        LoRa_Indicator = 'A';
        LoRa_Pingdicator = true;
      }
    }
    else if (LoRa_Pingdicator && Change) {
      if (LoRa_True)
      {
        LoRa_Indicator = 'M';
        LoRa_Pingdicator = false;
      }
    }
    if (!LoRa_True && Change) {
      LoRa_Indicator = '0';
    }
    if (Change2) {
      if (ESPNOW_True) {
        ESP_NOW_RSSI = RSSI;
        ESPnow_Strength = String(RSSI) + "dBm";
      }
      else {
        ESP_NOW_RSSI = 0;
        ESPnow_Strength = "???dBm";
      }
    }
    if (ESP_NOW_RSSI == 0) {
      ESP_NOW_ICONVAL = "0";
    }
    else if (ESP_NOW_RSSI < -70) {
      ESP_NOW_ICONVAL = "1";
    }
    else if (ESP_NOW_RSSI < -20) {
      ESP_NOW_ICONVAL = "2";
    }
    else {
      ESP_NOW_ICONVAL = "";
    }
    display.print(String(LoRa_Indicator) + " " + ESP_NOW_ICONVAL);
    display.setFont(NULL);
    display.setCursor(90, 0);
    display.print(ESPnow_Strength);
    display.setFont(NULL);
    display.display();
  }
}

// Home Fns
void Home_items_Selector(int State, int Encoder_Direction_Value) {
  bool Mode_Changed = false;
  if (State == 0)
  {
    if (Encoder_Direction_Value == 1) {
      if (Home_Counter >= Home_Countertotal) {
        Home_Counter = 0;
      }
      else {
        Home_Counter++;
      }
    }
    else if (Encoder_Direction_Value == 0) {
      if (Home_Counter <= 0) {
        Home_Counter = Home_Countertotal;
      }
      else {
        Home_Counter--;
      }
    }
  }
  if (State == 1) {
    // Changes to Message Compose
    if (Home_Counter == 0) {
      Current_Mode = 2;
      Msg_Compose_Message = "";
      Mode_Changed = true;
      Serial.println("   ----- MSG COMPOSER MODE -----   ");
      Msg_Compose_Fn_Init = true;
      Msg_Compose_Display_Renderer();
    }
    if (Home_Counter == 1) {
      Voice_Setup_flag = true;
      Mode_Changed = true;
      Current_Mode = 3;
      Serial.println("   ----- Voice MODE -----   ");
      xTaskCreatePinnedToCore(
          Voice_Loop,
          "Voice_Loop",
          20000,
          NULL,
          1,
          &Voice_Task_Handle,
          0);
      vTaskDelay(50 / portTICK_PERIOD_MS);
      // After this point Voice would have resumed this task
      Home_Display_Renderer();
    }
    if (Home_Counter == 2) {
      Mode_Changed = true;
      Current_Mode = 4;
      Serial.println("   ----- Prim MODE -----   ");
      xTaskCreatePinnedToCore(
          Simple_mode_Loop,
          "Simple_mode_Loop",
          20000,
          NULL,
          1,
          NULL,
          0);
    }
  }
  if (!Mode_Changed) {
    Home_Display_Renderer();
  }
}

void Home_Display_Renderer() {
  display.fillRect(0, 8, 128, 64, BLACK);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setFont(&Brolocatoricons);
  display.setCursor(Center_Bar_First.x, Center_Bar_First.y);
  display.println("H");
  display.setCursor(Center_Bar_Second.x, Center_Bar_Second.y);
  display.println("G");
  display.setCursor(Center_Bar_Third.x, Center_Bar_Third.y);
  display.println("D");
  display.setFont(NULL);
  if (Home_Counter == 0) {
    display.drawRect(13, 10, 25, 21, WHITE);
  }
  else if (Home_Counter == 1) {
    display.drawRect(51, 10, 25, 21, WHITE);
  }
  else {
    display.drawRect(91, 11, 25, 20, WHITE);
  }
  display.display();
  display2.clearDisplay();
  display2.setTextSize(1);
  display2.setTextColor(WHITE);
  if (All_Messages_Counter == 0)
  {
    display2.setFont(NULL);
    display2.setCursor(31, 10);
    display2.println("No Messages");
  }
  else {
    display2.setFont(NULL);
    display2.setCursor(0, 0);
    if (!debug_mode) {
      Serial.println(Current_Mode_Name[Current_Mode] + " - Latest: " + All_Messages[All_Messages_Counter - 1]);
    }
    display2.println("latest: " + All_Messages[All_Messages_Counter - 1]);
  }
  display2.setFont(&Brolocatoricons);
  display2.setCursor(Bottom_Bar_Second.x, Bottom_Bar_Second.y);
  display2.println("K");
  display2.setFont(NULL);
  display2.display();
  Status_Bar_Updater(false,false,false,false,0);
}

// Msg Compose Fns
void Msg_Compose_Counter_Updater(int direction){
  if (direction == 1) {
    if (Msg_Compose_Counter >= Msg_Compose_Countertotal) {
      Msg_Compose_Counter = 0; // Resets the Counter if counter value is more than or equal to the max size of the array
    }
    else {
      Msg_Compose_Counter++;
    }
    if (!debug_mode) {
        Serial.print(Current_Mode_Name[Current_Mode] + " - [ENCODER CW> ROTATION] Valve " + String(Msg_Compose_Counter) + "|" + StuffsArray[Msg_Compose_Counter] + "\n");
    }
  }
  else if (direction == 0) {
    if (Msg_Compose_Counter <= 0) {
        Msg_Compose_Counter = Msg_Compose_Countertotal;
    }
    else {
        Msg_Compose_Counter--;
    }
    if (!debug_mode) {
        Serial.print(Current_Mode_Name[Current_Mode] + " - [ENCODER CCW< ROTATION] Valve " + String(Msg_Compose_Counter) + "|" + StuffsArray[Msg_Compose_Counter]+ "\n");
      }
  }
  else {}
}

void Msg_Compose_Display_Renderer() {
  if (Msg_Compose_Counter != lastStateMsg_Compose_Counter || Msg_Compose_Fn_Init)
  {
    // Figures out what needs to be displayed in message compose letter carousel
    int ll;
    int lc;
    int rc;
    int rr;
    if ((Msg_Compose_Counter - 2) < 0)
    {
      if ((Msg_Compose_Counter - 1) < 0) {
      ll = Msg_Compose_Countertotal - 1;
      }
      else {
        ll = Msg_Compose_Countertotal;
      }
    }
    else
    {
      ll = Msg_Compose_Counter - 2;
    }
    if ((Msg_Compose_Counter - 1) < 0) {
      lc = Msg_Compose_Countertotal;
    } else {
      lc = Msg_Compose_Counter - 1;
    }
    if ((Msg_Compose_Counter + 1) > Msg_Compose_Countertotal)
    {
      rc = 0;
    }
    else
    {
      rc = Msg_Compose_Counter + 1;
    }
    if ((Msg_Compose_Counter + 2) > Msg_Compose_Countertotal) {
      if ((Msg_Compose_Counter + 1) > Msg_Compose_Countertotal) {
        rr = 1;
      }
      else {
        rr = 0;
      }
    } else {
      rr = Msg_Compose_Counter + 2;
    }
    // Display Output
    display.clearDisplay();
    display.setFont(NULL);
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 12);
    display.println(StuffsArray[ll]);
    display.setCursor(120, 12);
    display.println(StuffsArray[rr]);
    display.setTextSize(2);
    display.setCursor(17, 8);
    display.println(StuffsArray[lc]);
    display.setCursor(95, 8);
    display.println(StuffsArray[rc]);
    display.setTextSize(3);
    display.setCursor(55, 4);
    display.println(StuffsArray[Msg_Compose_Counter]);
    display.drawRect(50, 1, 25, 28, WHITE);
    display.display();
  }
  lastStateMsg_Compose_Counter = Msg_Compose_Counter;

  if (Msg_Compose_Message != LastStateOfMsg_Compose_Message || Msg_Compose_Fn_Init) {
    // Show Message that is composed
    display2.clearDisplay();
    display2.setFont(NULL);
    display2.setTextSize(1);
    display2.setTextColor(WHITE);
    display2.setCursor(0, 0);
    display2.println(Msg_Compose_Message);
    display2.setFont(&Brolocatoricons);
    display2.setCursor(Bottom_Bar_First.x ,Bottom_Bar_First.y);
    display2.println("C");
    display2.setCursor(Bottom_Bar_Second.x, Bottom_Bar_Second.y);
    display2.println("K");
    display2.setCursor(Bottom_Bar_Third.x, Bottom_Bar_Third.y);
    display2.println("F");
    display2.setFont(NULL);
    display2.display();
    Msg_Compose_Fn_Init = false;
  }
  LastStateOfMsg_Compose_Message = Msg_Compose_Message;
}

void Msg_Compose(int State, int Encoder_Direction_Value){
  
  if (State == 0) {  // Updates Displayed character in carousel
    Msg_Compose_Counter_Updater(Encoder_Direction_Value);
  }

  if (State == 1) {  // Adds Characters Into Message
    Serial.print(Current_Mode_Name[Current_Mode] + " - " +  String(StuffsArray[Msg_Compose_Counter]) + " Added to Message"+ "\n");
    if (Msg_Compose_Message.length() >= Msg_Max_Length) {
      Alert_displayer("Message Overflow", "Only " + String(Msg_Max_Length) + " Characters \nare allowed in a \nMessage!");
    }
    else {
      xSemaphoreTake(Message_Var_Semaphore, portMAX_DELAY);
      Msg_Compose_Message += StuffsArray[Msg_Compose_Counter];
      xSemaphoreGive(Message_Var_Semaphore);
    }
    if (Msg_Compose_Message == "FUCK")
    {
      display.clearDisplay();
      display.setTextSize(4);
      display.setTextColor(WHITE);
      display.setCursor(0, 0);
      display.println("FUCK");
      display.display();

      display2.clearDisplay();
      display2.setTextSize(4);
      display2.setTextColor(WHITE);
      display2.setCursor(0, 0);
      display2.println("YOU");
      display2.display();
      bool DisplayAccept = false;
      delay(200);
      while (!DisplayAccept)
      {
        if (Encoder_Switch()) {
          DisplayAccept = true;
        }
      }
      Msg_Compose_Fn_Init = true;
    }
  }

  if (State == 2) {  // Removes characters From Message
    Current_Mode = 1;
    Serial.println("   ----- HOME MODE -----   ");
    Home_Display_Renderer();
  }

  if (State == 4) {  // Removes characters From Message
    Serial.print(Current_Mode_Name[Current_Mode] + " - Removing Prev Char in Message\n");
    xSemaphoreTake(Message_Var_Semaphore, portMAX_DELAY);
    Msg_Compose_Message = Msg_Compose_Message.substring(0, Msg_Compose_Message.length() - 1);
    xSemaphoreGive(Message_Var_Semaphore);
  }

  if (State == 3) { // Sends Message
    xSemaphoreTake(Avail_To_Send_Semaphore, portMAX_DELAY);
    Avaliable_For_Send_Message = true;
    xSemaphoreGive(Avail_To_Send_Semaphore);
  }

  Msg_Compose_Display_Renderer();
}

// Voice Functions

void Voice_Main() {
  if (Voice_Setup_flag) {
    vTaskSuspend(Main_UI_Task_Handle);
    vTaskSuspend(Wireless_Task_Handle);
    eTaskState state1 = eTaskGetState(Main_UI_Task_Handle);
    eTaskState state2 = eTaskGetState(Wireless_Task_Handle);
    Serial.println((int)state1);
    Serial.println((int)state2);
    Voice_Setup_flag = false;
    display.clearDisplay();
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.setFont(NULL);
    display.setCursor(20, 12);
    display.println("Transmitting");
    display.setFont(NULL);
    display.display();
    display2.clearDisplay();
    display2.setFont(NULL);
    display2.setTextSize(1);
    display2.setTextColor(WHITE);
    display2.setFont(&Brolocatoricons);
    display2.setCursor(Bottom_Bar_First.x ,Bottom_Bar_First.y);
    display2.println("C");
    display2.setFont(NULL);
    display2.display();
  }
  size_t bytesRead;
  i2s_read(I2S_MIC_PORT, (void *)i2sBuffer, sizeof(i2sBuffer), &bytesRead, portMAX_DELAY);

  // send as raw PCM chunk
  size_t bytesToSend = min(bytesRead, (size_t)200); // limit to 200 bytes
  esp_err_t result = esp_now_send(ESP_NOW_PEER.peer_addr, (uint8_t *)i2sBuffer, bytesToSend);

  if (result != ESP_OK) {
    Serial.printf("Send failed! Error: %d  bytes=%u\n", result, bytesToSend);
  }

  if (Switch_Swl()) {
    Current_Mode = 1;
    vTaskResume(Main_UI_Task_Handle);
    vTaskResume(Wireless_Task_Handle);
    vTaskDelete(Voice_Task_Handle);
  }
}