From 6969c693688421a2072f5ebca1b3a91d8f2bfe47 Mon Sep 17 00:00:00 2001 From: ghassan Date: Tue, 10 Jun 2025 22:28:08 +0300 Subject: [PATCH] latest update --- src/game/code/code.ino | 218 --------------- src/game/code/code.ino/code.ino.ino | 117 ++++++++ src/game/code/code.ino/dice.h | 6 + src/game/code/code.ino/functions.ino | 127 +++++++++ src/game/code/code.ino/header.h | 25 ++ src/game/code/code.ino/i2c_functions.ino | 86 ++++++ src/joystic/code/code.ino | 218 --------------- src/joystic/code/code.ino/code.ino.ino | 103 +++++++ src/joystic/code/code.ino/functions.ino | 97 +++++++ src/joystic/code/code.ino/healthbar.h | 53 ++++ src/joystic/code/code.ino/map.h | 31 +++ src/joystic/code/code.ino/pins.h | 0 src/joystic/system_test/system_test.ino | 331 ++++++++++------------- 13 files changed, 790 insertions(+), 622 deletions(-) delete mode 100644 src/game/code/code.ino create mode 100644 src/game/code/code.ino/code.ino.ino create mode 100644 src/game/code/code.ino/dice.h create mode 100644 src/game/code/code.ino/functions.ino create mode 100644 src/game/code/code.ino/header.h create mode 100644 src/game/code/code.ino/i2c_functions.ino delete mode 100644 src/joystic/code/code.ino create mode 100644 src/joystic/code/code.ino/code.ino.ino create mode 100644 src/joystic/code/code.ino/functions.ino create mode 100644 src/joystic/code/code.ino/healthbar.h create mode 100644 src/joystic/code/code.ino/map.h create mode 100644 src/joystic/code/code.ino/pins.h diff --git a/src/game/code/code.ino b/src/game/code/code.ino deleted file mode 100644 index 45ece87..0000000 --- a/src/game/code/code.ino +++ /dev/null @@ -1,218 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#undef WAIT // Prevent macro conflict with FastLED - -// ============ PIN DEFINITIONS ============ -// PublicI2C (slave) pins -#define PUBLIC_I2C_SDA 21 -#define PUBLIC_I2C_SCL 22 -#define PUBLIC_I2C_ADDR 0x42 // Example slave address - -// LocalI2C (master) pins -#define LOCAL_I2C_SDA 12 -#define LOCAL_I2C_SCL 11 - -// OLED display settings -#define SCREEN_WIDTH 128 -#define SCREEN_HEIGHT 64 -#define OLED_RESET -1 - -// Joystick pins -#define JOY_X_PIN 1 // ADC1_CH0 -#define JOY_Y_PIN 2 // ADC1_CH1 -#define JOY_BTN_PIN 3 // Digital input - -// FastLED (NeoPixel) settings -#define NUM_LEDS 16 -#define LED_DATA_PIN 5 // Example GPIO for LED data - -// DotStar HD 8x8 Grid settings -#define DOTSTAR_WIDTH 8 -#define DOTSTAR_HEIGHT 8 -#define DOTSTAR_DATA 6 // Example GPIO for DotStar data -#define DOTSTAR_CLK 7 // Example GPIO for DotStar clock - -// ============ I2C BUS OBJECTS ============ -TwoWire PublicI2C = TwoWire(0); // I2C0 (slave) -TwoWire LocalI2C = TwoWire(1); // I2C1 (master) - -// ============ DEVICE OBJECTS ============= -Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &LocalI2C, OLED_RESET); -// Use a SparkFun_APDS9960 library that supports TwoWire -SparkFun_APDS9960 apds(&LocalI2C); -CRGB leds[NUM_LEDS]; -Adafruit_DotStarMatrix dotstar = Adafruit_DotStarMatrix( - DOTSTAR_WIDTH, DOTSTAR_HEIGHT, DOTSTAR_DATA, DOTSTAR_CLK, - DS_MATRIX_TOP + DS_MATRIX_LEFT + DS_MATRIX_ROWS + DS_MATRIX_PROGRESSIVE, - DOTSTAR_BRG -); - -// ============ DATA STRUCTURES ============ -struct SensorData { - int8_t joystickDir; // -1=none, 0=up, 1=down, 2=left, 3=right - bool joystickBtn; - uint16_t colorR, colorG, colorB, colorC; -}; -volatile SensorData latestData; - -// ============ I2C SLAVE DATA HANDLERS ========= -void receiveEvent(int numBytes) { - // Not used in this application, but required by Wire -} - -void requestEvent() { - // Copy volatile to local to avoid race conditions - SensorData copy; - noInterrupts(); - copy = latestData; - interrupts(); - // Send as a binary buffer - PublicI2C.write((uint8_t*)©, sizeof(SensorData)); -} - -// ============ JOYSTICK INTERPRETATION ========= -#define JOY_THRESHOLD_HIGH 3000 -#define JOY_THRESHOLD_LOW 1000 - -void updateJoystick(SensorData &data) { - int joyX = analogRead(JOY_X_PIN); - int joyY = analogRead(JOY_Y_PIN); - bool joyBtn = digitalRead(JOY_BTN_PIN) == LOW; - - // Default: no direction - data.joystickDir = -1; - - if (joyY > JOY_THRESHOLD_HIGH) data.joystickDir = 0; // Up - else if (joyY < JOY_THRESHOLD_LOW) data.joystickDir = 1; // Down - else if (joyX < JOY_THRESHOLD_LOW) data.joystickDir = 2; // Left - else if (joyX > JOY_THRESHOLD_HIGH) data.joystickDir = 3; // Right - - data.joystickBtn = joyBtn; -} - -// ============ COLOR SENSOR READING ========= -void updateColorSensor(SensorData &data) { - uint16_t r=0, g=0, b=0, c=0; - if (apds.readAmbientLight(c) && - apds.readRedLight(r) && - apds.readGreenLight(g) && - apds.readBlueLight(b)) { - data.colorR = r; - data.colorG = g; - data.colorB = b; - data.colorC = c; - } -} - -// ============ DISPLAY LOGIC ========= -void updateDisplays(const SensorData &data) { - // DotStar: show direction as arrow or color as background - dotstar.fillScreen(0); - if (data.joystickDir == 0) dotstar.drawPixel(3, 0, dotstar.Color(0,0,255)); // Up - else if (data.joystickDir == 1) dotstar.drawPixel(3, 7, dotstar.Color(0,0,255)); // Down - else if (data.joystickDir == 2) dotstar.drawPixel(0, 3, dotstar.Color(0,0,255)); // Left - else if (data.joystickDir == 3) dotstar.drawPixel(7, 3, dotstar.Color(0,0,255)); // Right - else dotstar.fillScreen(dotstar.Color(data.colorR>>2, data.colorG>>2, data.colorB>>2)); // Show color - dotstar.show(); - - // FastLED: color bar with button brightness - uint8_t brightness = data.joystickBtn ? 255 : 64; - for (int i = 0; i < NUM_LEDS; i++) { - leds[i] = CRGB(data.colorR>>4, data.colorG>>4, data.colorB>>4); - leds[i].nscale8_video(brightness); - } - FastLED.show(); - - // OLED: show values - display.clearDisplay(); - display.setCursor(0,0); - display.print("Dir: "); - switch (data.joystickDir) { - case 0: display.println("Up"); break; - case 1: display.println("Down"); break; - case 2: display.println("Left"); break; - case 3: display.println("Right"); break; - default: display.println("None"); break; - } - display.print("Btn: "); display.println(data.joystickBtn ? "Pressed" : "Released"); - display.print("R: "); display.println(data.colorR); - display.print("G: "); display.println(data.colorG); - display.print("B: "); display.println(data.colorB); - display.print("C: "); display.println(data.colorC); - display.display(); -} - -// ============ SETUP FUNCTION ============= -void setup() { - Serial.begin(115200); - - // --- Initialize PublicI2C as Slave --- - PublicI2C.begin(PUBLIC_I2C_ADDR, PUBLIC_I2C_SDA, PUBLIC_I2C_SCL, 100000); - PublicI2C.onReceive(receiveEvent); - PublicI2C.onRequest(requestEvent); - Serial.println("PublicI2C (slave) initialized."); - - // --- Initialize LocalI2C as Master --- - LocalI2C.begin(LOCAL_I2C_SDA, LOCAL_I2C_SCL, 100000); - Serial.println("LocalI2C (master) initialized."); - - // --- Initialize OLED Display --- - if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { - Serial.println("SSD1306 allocation failed"); - while (1); - } - display.clearDisplay(); - display.setTextSize(1); - display.setTextColor(SSD1306_WHITE); - display.setCursor(0,0); - display.println("OLED Ready!"); - display.display(); - - // --- Initialize APDS-9960 (SparkFun) --- - if (!apds.init()) { // Uses LocalI2C if library supports it - Serial.println("APDS-9960 initialization failed"); - display.println("No APDS-9960!"); - display.display(); - while (1); - } - display.println("APDS-9960 ready!"); - display.display(); - - // Enable color sensing - apds.enableLightSensor(false); - - // --- Initialize Joystick Pins --- - pinMode(JOY_BTN_PIN, INPUT_PULLUP); // Button is active LOW - - // --- Initialize FastLED (NeoPixel) --- - FastLED.addLeds(leds, NUM_LEDS); - FastLED.clear(); - FastLED.show(); - - // --- Initialize DotStar Matrix --- - dotstar.begin(); - dotstar.setBrightness(32); // Adjust as needed - dotstar.fillScreen(0); - dotstar.show(); -} - -// ============ MAIN LOOP ================== -void loop() { - SensorData tempData; - updateJoystick(tempData); - updateColorSensor(tempData); - - // Copy to shared struct for I2C - noInterrupts(); - latestData = tempData; - interrupts(); - - updateDisplays(tempData); - - delay(50); // Adjust as needed -} \ No newline at end of file diff --git a/src/game/code/code.ino/code.ino.ino b/src/game/code/code.ino/code.ino.ino new file mode 100644 index 0000000..85e43d1 --- /dev/null +++ b/src/game/code/code.ino/code.ino.ino @@ -0,0 +1,117 @@ +#include "dice.h" // Dice Function +#include "header.h" // Player Data Types +#include + +#define LED_PIN 8 // Digital pin connected to the LED strip +#define NUM_LEDS 64 // 8x8 = 64 LEDs +#define BRIGHTNESS 100 // Default max brightness + +#define sspacer Serial.println("--------------------------------------------") +#define dspacer Serial.println("============================================") + +Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800); + +// Convert (row, col) to strip index +uint16_t getIndex(uint8_t row, uint8_t col) { + // Adjust depending on how your strip is wired + if (row % 2 == 0) { + return row * 8 + col; // Left to right + } else { + return row * 8 + (7 - col); // Right to left (zigzag) + } +} + +// Set individual LED with row, col, color and brightness +void setPixelColorRC(uint8_t row, uint8_t col, uint8_t r, uint8_t g, uint8_t b, uint8_t brightness) { + if(row >= 8 || col >= 8) return; // Bounds check + strip.setBrightness(brightness); + uint16_t index = getIndex(row, col); + strip.setPixelColor(index, strip.Color(r, g, b)); + strip.show(); +} + +// Optional: set LED by index directly +void setPixelColorIndex(uint16_t index, uint8_t r, uint8_t g, uint8_t b, uint8_t brightness) { + if (index >= NUM_LEDS) return; + + strip.setBrightness(brightness); + strip.setPixelColor(index, strip.Color(r, g, b)); + strip.show(); +} + +//================================================================ +// SETUP +//================================================================ + + void setup() { + + // I2C Communications + Wire.begin(); // For Master + + // Start Serial And Message + Serial.begin(115200); + Serial.println(); + dspacer; + + // Starting LED Strip + strip.begin(); + strip.setBrightness(BRIGHTNESS); // Initial brightness + strip.show(); // Initialize all pixels to 'off' + + // Red Player + player[0].i2ca = 0x10; + player[0].position.x = 0; + player[0].position.y = 0; + player[0].color.r = 255; + player[0].color.i = 60; + + // Paint The Strip Position For Red Player + setPixelColorRC( + player[0].position.x, + player[0].position.y, + player[0].color.r, + player[0].color.g, + player[0].color.b, + player[0].color.i + ); + + // Blue Player + player[1].i2ca = 0x20; + player[1].position.x = 7; + player[1].position.y = 7; + player[1].color.b = 255; + player[1].color.i = 60; + + // Paint The Strip Position For Blue Player + setPixelColorRC( + player[1].position.x, + player[1].position.y, + player[1].color.r, + player[1].color.g, + player[1].color.b, + player[1].color.i + ); + + // Make Dicision + diceRoll(); + + // Make Spacer + dspacer; + + } + +//================================================================ +// LOOP +//================================================================ + + void loop() { + + for(int i=0; i<2; i++) { + movePlayers(i); + } + + } + +//================================================================ +// +//================================================================ \ No newline at end of file diff --git a/src/game/code/code.ino/dice.h b/src/game/code/code.ino/dice.h new file mode 100644 index 0000000..7da0bac --- /dev/null +++ b/src/game/code/code.ino/dice.h @@ -0,0 +1,6 @@ + #include // For esp_random() + + int roll_dice() { + uint32_t random_value = esp_random(); + return (random_value % 6) + 1; + } \ No newline at end of file diff --git a/src/game/code/code.ino/functions.ino b/src/game/code/code.ino/functions.ino new file mode 100644 index 0000000..182be9b --- /dev/null +++ b/src/game/code/code.ino/functions.ino @@ -0,0 +1,127 @@ + void diceRoll() { + + dspacer; + Serial.println(" Dice Roll"); + dspacer; + + while(1) { + + // Player turn decision + int redplayerdice = roll_dice(); + int blueplayerdice = roll_dice(); + + // Display The Dice Values + Serial.println("Red Dice : " + String(redplayerdice)); + Serial.println("Blue Dice : " + String(blueplayerdice)); + + // Swaping The Players + if(redplayerdice > blueplayerdice) { + Serial.println("Red Player Starts"); + break; + } else if(redplayerdice < blueplayerdice) { + Serial.println("Blue Player Starts"); + temp = player[0]; + player[0] = player[1]; + player[1] = temp; + break; + } else if(redplayerdice == blueplayerdice) { + Serial.println(" -X- Its A Draw, Do It Again"); + } + + } + + } + +//================================================================ +// +//================================================================ + + String Question(Stream &serial, String Message) { + + // Print On Serial + serial.print(Message + " : "); + + // Wait Until User Input A Thing + while(!serial.available()); + + // Read User Input + String x = serial.readStringUntil('\n'); + + // Cleaning The Buffer + while(serial.available()) { serial.read(); } + + // Remove Spaces + x.trim(); + + // Print Answer + serial.println(x); + + // Return The Value Of x + return x; + + } + +//================================================================ +// +//================================================================ + + void movePlayers(uint8_t num) { + + // New Position Variables + uint8_t posX, posY; + + // Select Player + if(player[num].color.r == 255) { + Serial.println("Red Player Turn > > >"); + } else if(player[num].color.b == 255) { + Serial.println("Blue Player Turn > > >"); + } + + // Take User Input + while(1) { + + // User Input + posX = Question(Serial, "Select X Position ").toInt(); + posY = Question(Serial, "Select Y Position ").toInt(); + + // Boundries Check + if((posX >= 0 && posX <= 7) && (posY >= 0 && posY <= 7)) { + break; + } else { + Serial.println(" -> Wrong Input, Exceeding Boundries, Try Again"); + } + + } + + // Seperator + Serial.println("--------------------------------------------"); + + // Clear Current Position + setPixelColorRC( + player[num].position.x, + player[num].position.y, + 0, + 0, + 0, + 60 + ); + + // Update Positions Values + player[num].position.x = posX; + player[num].position.y = posY; + + // Paint New Position + setPixelColorRC( + player[num].position.x, + player[num].position.y, + player[num].color.r, + player[num].color.g, + player[num].color.b, + player[num].color.i + ); + + } + +//================================================================ +// +//================================================================ \ No newline at end of file diff --git a/src/game/code/code.ino/header.h b/src/game/code/code.ino/header.h new file mode 100644 index 0000000..2228533 --- /dev/null +++ b/src/game/code/code.ino/header.h @@ -0,0 +1,25 @@ + // Player Position Data Type + struct _position { + uint8_t x; + uint8_t y; + }; + + // Color Of Any Thing + struct _color { + uint8_t r; // Red Color + uint8_t g; // Green Color + uint8_t b; // Blue Color + uint8_t i; // Intensity + }; + + // Player Data Type + struct _player { + _position position; // the current position of the player + _color color; // the color of the player light indicator + uint8_t health; // the health level of the player 0 - 7 => 8 + uint8_t i2ca; // the i2c address of the joystic of the player + }; + + // Two Players Instences + _player player[2]; // The Two Contenders + _player temp; // For Swaping Purpose \ No newline at end of file diff --git a/src/game/code/code.ino/i2c_functions.ino b/src/game/code/code.ino/i2c_functions.ino new file mode 100644 index 0000000..d0620f0 --- /dev/null +++ b/src/game/code/code.ino/i2c_functions.ino @@ -0,0 +1,86 @@ + + int I2C_DiceCommand(uint8_t address) { + + // Memory + int dice = 0; + + // Call Slave Addrees + Wire.beginTransmission(address); // or 0x20 + + // Send Command 1 -> Roll A Dice + Wire.write(0x01); + + // Stop Transmition + Wire.endTransmission(); + + // Request 1 byte from slave -> Contains A Number 1 to 6 + Wire.requestFrom(0x10, 1); + + // If Data Received + if(Wire.available()) { + + // Read The Data + dice = Wire.read(); + + } + + // Return The Value To Master + return dice + + } + + void I2C_PushData(uint8_t address, _player &pl1, _player &pl2) { + + // Slave Address + Wire.beginTransmission(address); + + // Command Number - Push Data + Wire.write(0x02); + + // Player One Data + Wire.write(pl1.position.x); + Wire.write(pl1.position.y); + Wire.write(pl1.color.r); + Wire.write(pl1.color.g); + Wire.write(pl1.color.b); + Wire.write(pl1.color.i); + Wire.write(pl1.health); + + // Player Two Data + Wire.write(pl1.position.x); + Wire.write(pl1.position.y); + Wire.write(pl1.color.r); + Wire.write(pl1.color.g); + Wire.write(pl1.color.b); + Wire.write(pl1.color.i); + Wire.write(pl1.health); + + // Stop Transmition + Wire.endTransmission(); + + } + + void I2C_Permission(uint8_t address) { + + // Card Color + _color color; + + // Direction + uint8_t Direction; + + Wire.beginTransmission(address); + Wire.write(0x03); // permission to play command + Wire.endTransmission(); + + // Master waits for slave to send data + Wire.requestFrom(0x10, 4); // expecting 2 bytes: card color (R, G, B), direction (one byte) + + // Receive Bytes + if(Wire.available()) { + color.r = Wire.read(); + color.g = Wire.read(); + color.b = Wire.read(); + Direction = Wire.read(); + } + + } \ No newline at end of file diff --git a/src/joystic/code/code.ino b/src/joystic/code/code.ino deleted file mode 100644 index 45ece87..0000000 --- a/src/joystic/code/code.ino +++ /dev/null @@ -1,218 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#undef WAIT // Prevent macro conflict with FastLED - -// ============ PIN DEFINITIONS ============ -// PublicI2C (slave) pins -#define PUBLIC_I2C_SDA 21 -#define PUBLIC_I2C_SCL 22 -#define PUBLIC_I2C_ADDR 0x42 // Example slave address - -// LocalI2C (master) pins -#define LOCAL_I2C_SDA 12 -#define LOCAL_I2C_SCL 11 - -// OLED display settings -#define SCREEN_WIDTH 128 -#define SCREEN_HEIGHT 64 -#define OLED_RESET -1 - -// Joystick pins -#define JOY_X_PIN 1 // ADC1_CH0 -#define JOY_Y_PIN 2 // ADC1_CH1 -#define JOY_BTN_PIN 3 // Digital input - -// FastLED (NeoPixel) settings -#define NUM_LEDS 16 -#define LED_DATA_PIN 5 // Example GPIO for LED data - -// DotStar HD 8x8 Grid settings -#define DOTSTAR_WIDTH 8 -#define DOTSTAR_HEIGHT 8 -#define DOTSTAR_DATA 6 // Example GPIO for DotStar data -#define DOTSTAR_CLK 7 // Example GPIO for DotStar clock - -// ============ I2C BUS OBJECTS ============ -TwoWire PublicI2C = TwoWire(0); // I2C0 (slave) -TwoWire LocalI2C = TwoWire(1); // I2C1 (master) - -// ============ DEVICE OBJECTS ============= -Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &LocalI2C, OLED_RESET); -// Use a SparkFun_APDS9960 library that supports TwoWire -SparkFun_APDS9960 apds(&LocalI2C); -CRGB leds[NUM_LEDS]; -Adafruit_DotStarMatrix dotstar = Adafruit_DotStarMatrix( - DOTSTAR_WIDTH, DOTSTAR_HEIGHT, DOTSTAR_DATA, DOTSTAR_CLK, - DS_MATRIX_TOP + DS_MATRIX_LEFT + DS_MATRIX_ROWS + DS_MATRIX_PROGRESSIVE, - DOTSTAR_BRG -); - -// ============ DATA STRUCTURES ============ -struct SensorData { - int8_t joystickDir; // -1=none, 0=up, 1=down, 2=left, 3=right - bool joystickBtn; - uint16_t colorR, colorG, colorB, colorC; -}; -volatile SensorData latestData; - -// ============ I2C SLAVE DATA HANDLERS ========= -void receiveEvent(int numBytes) { - // Not used in this application, but required by Wire -} - -void requestEvent() { - // Copy volatile to local to avoid race conditions - SensorData copy; - noInterrupts(); - copy = latestData; - interrupts(); - // Send as a binary buffer - PublicI2C.write((uint8_t*)©, sizeof(SensorData)); -} - -// ============ JOYSTICK INTERPRETATION ========= -#define JOY_THRESHOLD_HIGH 3000 -#define JOY_THRESHOLD_LOW 1000 - -void updateJoystick(SensorData &data) { - int joyX = analogRead(JOY_X_PIN); - int joyY = analogRead(JOY_Y_PIN); - bool joyBtn = digitalRead(JOY_BTN_PIN) == LOW; - - // Default: no direction - data.joystickDir = -1; - - if (joyY > JOY_THRESHOLD_HIGH) data.joystickDir = 0; // Up - else if (joyY < JOY_THRESHOLD_LOW) data.joystickDir = 1; // Down - else if (joyX < JOY_THRESHOLD_LOW) data.joystickDir = 2; // Left - else if (joyX > JOY_THRESHOLD_HIGH) data.joystickDir = 3; // Right - - data.joystickBtn = joyBtn; -} - -// ============ COLOR SENSOR READING ========= -void updateColorSensor(SensorData &data) { - uint16_t r=0, g=0, b=0, c=0; - if (apds.readAmbientLight(c) && - apds.readRedLight(r) && - apds.readGreenLight(g) && - apds.readBlueLight(b)) { - data.colorR = r; - data.colorG = g; - data.colorB = b; - data.colorC = c; - } -} - -// ============ DISPLAY LOGIC ========= -void updateDisplays(const SensorData &data) { - // DotStar: show direction as arrow or color as background - dotstar.fillScreen(0); - if (data.joystickDir == 0) dotstar.drawPixel(3, 0, dotstar.Color(0,0,255)); // Up - else if (data.joystickDir == 1) dotstar.drawPixel(3, 7, dotstar.Color(0,0,255)); // Down - else if (data.joystickDir == 2) dotstar.drawPixel(0, 3, dotstar.Color(0,0,255)); // Left - else if (data.joystickDir == 3) dotstar.drawPixel(7, 3, dotstar.Color(0,0,255)); // Right - else dotstar.fillScreen(dotstar.Color(data.colorR>>2, data.colorG>>2, data.colorB>>2)); // Show color - dotstar.show(); - - // FastLED: color bar with button brightness - uint8_t brightness = data.joystickBtn ? 255 : 64; - for (int i = 0; i < NUM_LEDS; i++) { - leds[i] = CRGB(data.colorR>>4, data.colorG>>4, data.colorB>>4); - leds[i].nscale8_video(brightness); - } - FastLED.show(); - - // OLED: show values - display.clearDisplay(); - display.setCursor(0,0); - display.print("Dir: "); - switch (data.joystickDir) { - case 0: display.println("Up"); break; - case 1: display.println("Down"); break; - case 2: display.println("Left"); break; - case 3: display.println("Right"); break; - default: display.println("None"); break; - } - display.print("Btn: "); display.println(data.joystickBtn ? "Pressed" : "Released"); - display.print("R: "); display.println(data.colorR); - display.print("G: "); display.println(data.colorG); - display.print("B: "); display.println(data.colorB); - display.print("C: "); display.println(data.colorC); - display.display(); -} - -// ============ SETUP FUNCTION ============= -void setup() { - Serial.begin(115200); - - // --- Initialize PublicI2C as Slave --- - PublicI2C.begin(PUBLIC_I2C_ADDR, PUBLIC_I2C_SDA, PUBLIC_I2C_SCL, 100000); - PublicI2C.onReceive(receiveEvent); - PublicI2C.onRequest(requestEvent); - Serial.println("PublicI2C (slave) initialized."); - - // --- Initialize LocalI2C as Master --- - LocalI2C.begin(LOCAL_I2C_SDA, LOCAL_I2C_SCL, 100000); - Serial.println("LocalI2C (master) initialized."); - - // --- Initialize OLED Display --- - if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { - Serial.println("SSD1306 allocation failed"); - while (1); - } - display.clearDisplay(); - display.setTextSize(1); - display.setTextColor(SSD1306_WHITE); - display.setCursor(0,0); - display.println("OLED Ready!"); - display.display(); - - // --- Initialize APDS-9960 (SparkFun) --- - if (!apds.init()) { // Uses LocalI2C if library supports it - Serial.println("APDS-9960 initialization failed"); - display.println("No APDS-9960!"); - display.display(); - while (1); - } - display.println("APDS-9960 ready!"); - display.display(); - - // Enable color sensing - apds.enableLightSensor(false); - - // --- Initialize Joystick Pins --- - pinMode(JOY_BTN_PIN, INPUT_PULLUP); // Button is active LOW - - // --- Initialize FastLED (NeoPixel) --- - FastLED.addLeds(leds, NUM_LEDS); - FastLED.clear(); - FastLED.show(); - - // --- Initialize DotStar Matrix --- - dotstar.begin(); - dotstar.setBrightness(32); // Adjust as needed - dotstar.fillScreen(0); - dotstar.show(); -} - -// ============ MAIN LOOP ================== -void loop() { - SensorData tempData; - updateJoystick(tempData); - updateColorSensor(tempData); - - // Copy to shared struct for I2C - noInterrupts(); - latestData = tempData; - interrupts(); - - updateDisplays(tempData); - - delay(50); // Adjust as needed -} \ No newline at end of file diff --git a/src/joystic/code/code.ino/code.ino.ino b/src/joystic/code/code.ino/code.ino.ino new file mode 100644 index 0000000..da77a4c --- /dev/null +++ b/src/joystic/code/code.ino/code.ino.ino @@ -0,0 +1,103 @@ +#include "pins.h" +#include +#include "healthbar.h" +#include "map.h" + +#define X_PIN 1 +#define Y_PIN 2 +#define BUTTON_PIN 3 +#define DEAD_ZONE 50 // Adjust this value for your joystick sensitivity + +struct _location { + uint8_t x; + uint8_t y; +}; + +_location playerLocation; + +void setup() { + + playerLocation.x = 0; + playerLocation.y = 7; + + Serial.begin(9600); + while (!Serial); // Wait for serial monitor on boards like Leonardo + + map_begin(); + + // Display Helth + fastled_begin(); + red_health(4, 5); + blue_health(2, 5); + fastled_show(); + + // map display - map_setDot(int x, int y, byte r, byte g, byte b) + map_setDot(0, 7, 255, 0, 0, 5); + map_setDot(7, 0, 0, 0, 255, 5); + map_show(); + + // // Initialize I2C buses (example for ESP32) + // Wire.begin(6, 7); // Public I2C (SDA 6, SCL 7) + // Wire1.begin(12, 11); // Local I2C (SDA 12, SCL 11) - remove if not available + +} + +void loop() { + + // Serial.println(String(analogRead(X_PIN)) + " " + String(analogRead(Y_PIN))); + // delay(250); + + String joymem = readJoystick(); + Serial.println(joymem); + + if(joymem == "up") { + if(playerLocation.y < 7) { + // Clear Previous playerLocation + map_setDot(playerLocation.x, playerLocation.y, 0, 0, 0, 0); + // New Value + playerLocation.y += 1; + // Draw On New playerLocation + map_setDot(playerLocation.x, playerLocation.y, 255, 0, 0, 50); + // Display On Map + map_show(); + delay(500); + } + } else if(joymem == "down") { + if(playerLocation.y > 0) { + // Clear Previous playerLocation + map_setDot(playerLocation.x, playerLocation.y, 0, 0, 0, 0); + // New Value + playerLocation.y -= 1; + // Draw On New playerLocation + map_setDot(playerLocation.x, playerLocation.y, 255, 0, 0, 50); + // Display On Map + map_show(); + delay(500); + } + } else if(joymem == "left") { + if(playerLocation.x > 0) { + // Clear Previous playerLocation + map_setDot(playerLocation.x, playerLocation.y, 0, 0, 0, 0); + // New Value + playerLocation.x -= 1; + // Draw On New playerLocation + map_setDot(playerLocation.x, playerLocation.y, 255, 0, 0, 50); + // Display On Map + map_show(); + delay(500); + } + } else if(joymem == "right") { + if(playerLocation.x < 7) { + // Clear Previous playerLocation + map_setDot(playerLocation.x, playerLocation.y, 0, 0, 0, 0); + // New Value + playerLocation.x += 1; + // Draw On New playerLocation + map_setDot(playerLocation.x, playerLocation.y, 255, 0, 0, 50); + // Display On Map + map_show(); + delay(500); + } + } + +} diff --git a/src/joystic/code/code.ino/functions.ino b/src/joystic/code/code.ino/functions.ino new file mode 100644 index 0000000..8b5134e --- /dev/null +++ b/src/joystic/code/code.ino/functions.ino @@ -0,0 +1,97 @@ + + // I2C scanner function + void scanI2CBus(TwoWire &wire, const char* busName) { + + byte error, address; + int nDevices = 0; + Serial.print("Scanning I2C bus: "); + Serial.println(busName); + for(address = 1; address < 127; address++) { + wire.beginTransmission(address); + error = wire.endTransmission(); + if (error == 0) { + Serial.print("I2C device found at address 0x"); + if (address < 16) Serial.print("0"); + Serial.print(address, HEX); + Serial.println(" !"); + nDevices++; + } else if (error == 4) { + Serial.print("Unknown error at address 0x"); + if (address < 16) Serial.print("0"); + Serial.println(address, HEX); + } + } + if (nDevices == 0) + Serial.println("No I2C devices found\n"); + else + Serial.println("done\n"); + + } + +//================================================================ +// +//================================================================ + + String readJoystick() { + + // const int X_PIN = A0; + // const int Y_PIN = A1; + int xVal = analogRead(X_PIN); + int yVal = analogRead(Y_PIN); + + // Deadzone centers and ranges (after increasing by 50) + const int X_DEADZONE_MIN = 1975; + const int X_DEADZONE_MAX = 2065; + const int Y_DEADZONE_MIN = 1875; + const int Y_DEADZONE_MAX = 1965; + + // Deadzone centers (can be calculated as (min+max)/2) + const int X_CENTER = (X_DEADZONE_MIN + X_DEADZONE_MAX) / 2; // 2020 + const int Y_CENTER = (Y_DEADZONE_MIN + Y_DEADZONE_MAX) / 2; // 1920 + + bool xInDeadzone = (xVal >= X_DEADZONE_MIN && xVal <= X_DEADZONE_MAX); + bool yInDeadzone = (yVal >= Y_DEADZONE_MIN && yVal <= Y_DEADZONE_MAX); + + if (xInDeadzone && yInDeadzone) return "center"; + + // Calculate how far each axis is from its deadzone center + int xDist = abs(xVal - X_CENTER); + int yDist = abs(yVal - Y_CENTER); + + // If both axes are outside their deadzones, choose the one with the greater movement + if (!xInDeadzone && !yInDeadzone) { + if (xDist > yDist) { + if (xVal < X_CENTER) return "left"; + else return "right"; + } else { + if (yVal < Y_CENTER) return "up"; + else return "down"; + } + } + // If only one axis is outside, return its direction + else if (!yInDeadzone) { + if (yVal < Y_CENTER) return "up"; + else return "down"; + } + else if (!xInDeadzone) { + if (xVal < X_CENTER) return "left"; + else return "right"; + } + + return "center"; + + } + +//================================================================ +// +//================================================================ + + int analogReadAVG(uint8_t pin, uint8_t times) { + + int value; + + for(int i=0; i + +#define NUM_LEDS 16 +#define DATA_PIN 8 // Change to your actual data pin + +CRGB leds[NUM_LEDS]; + +void fastled_color(int start, int end, byte r, byte g, byte b, byte brightness) { + if (start < 0) start = 0; + if (end >= NUM_LEDS) end = NUM_LEDS - 1; + + CHSV hsv = rgb2hsv_approximate(CRGB(r, g, b)); + hsv.value = brightness; + + for (int i = start; i <= end; i++) { + leds[i] = hsv; + } +} + +void fastled_begin() { + FastLED.addLeds(leds, NUM_LEDS); + FastLED.clear(); + FastLED.show(); +} + +void fastled_show() { + FastLED.show(); +} + +// Example health bar functions +void red_health(uint8_t value, uint8_t brightness) { + fastled_color(0, value-1, 255, 0, 0, brightness); +} + +void blue_health(uint8_t value, uint8_t brightness) { + fastled_color(8, 8+value-1, 0, 0, 255, brightness); // Adjust if you want a different range +} + +void crossfade_red() { + + for(int i=10; i<=60; i++){ + red_health(4, i); + fastled_show(); + delay(20); + } + + for(int i=60; i>=10; i--) { + red_health(4, i); + fastled_show(); + delay(20); + } + +} \ No newline at end of file diff --git a/src/joystic/code/code.ino/map.h b/src/joystic/code/code.ino/map.h new file mode 100644 index 0000000..d165c10 --- /dev/null +++ b/src/joystic/code/code.ino/map.h @@ -0,0 +1,31 @@ +#include + +#define DATAPIN 10 // Change to your data pin +#define CLOCKPIN 9 // Change to your clock pin +#define NUMPIXELS 64 // 8x8 matrix + +Adafruit_DotStar matrix(NUMPIXELS, DATAPIN, CLOCKPIN, DOTSTAR_BGR); + +// Function to set a single dot (x, y) to a color (r, g, b) +void map_setDot(int x, int y, byte r, byte g, byte b, byte brightness) { + if (x < 0 || x > 7 || y < 0 || y > 7) return; // Out of bounds + int index = x + y * 8; // Convert (x,y) to strip index + + // Scale the color by brightness (0–255) + uint32_t color = matrix.Color( + (uint8_t)(r * brightness / 255), + (uint8_t)(g * brightness / 255), + (uint8_t)(b * brightness / 255) + ); + matrix.setPixelColor(index, color); +} + +void map_begin() { + matrix.begin(); + matrix.clear(); + matrix.show(); +} + +void map_show() { + matrix.show(); +} \ No newline at end of file diff --git a/src/joystic/code/code.ino/pins.h b/src/joystic/code/code.ino/pins.h new file mode 100644 index 0000000..e69de29 diff --git a/src/joystic/system_test/system_test.ino b/src/joystic/system_test/system_test.ino index 45ece87..4f4c039 100644 --- a/src/joystic/system_test/system_test.ino +++ b/src/joystic/system_test/system_test.ino @@ -1,218 +1,177 @@ -#include -#include -#include -#include -#include -#include -#include -#undef WAIT // Prevent macro conflict with FastLED + #include + #include + #include + #include + #include + #include -// ============ PIN DEFINITIONS ============ -// PublicI2C (slave) pins -#define PUBLIC_I2C_SDA 21 -#define PUBLIC_I2C_SCL 22 -#define PUBLIC_I2C_ADDR 0x42 // Example slave address +// ============ PIN DEFINITIONS (ESP32-S3 Super Mini) ============ -// LocalI2C (master) pins -#define LOCAL_I2C_SDA 12 -#define LOCAL_I2C_SCL 11 + #define JOY_X_PIN A1 // Example: GP2, adjust to your wiring + #define JOY_Y_PIN A2 // Example: GP3, adjust to your wiring + #define JOY_BTN_PIN 3 // Example: GP8, adjust to your wiring -// OLED display settings -#define SCREEN_WIDTH 128 -#define SCREEN_HEIGHT 64 -#define OLED_RESET -1 + #define LOCAL_I2C_SDA 12 // Example: GP9, SDA for OLED/APDS + #define LOCAL_I2C_SCL 11 // Example: GP10, SCL for OLED/APDS -// Joystick pins -#define JOY_X_PIN 1 // ADC1_CH0 -#define JOY_Y_PIN 2 // ADC1_CH1 -#define JOY_BTN_PIN 3 // Digital input + #define NUM_LEDS 16 + #define LED_DATA_PIN 8 // Example: GP11, adjust to your wiring -// FastLED (NeoPixel) settings -#define NUM_LEDS 16 -#define LED_DATA_PIN 5 // Example GPIO for LED data + #define DOTSTAR_WIDTH 8 + #define DOTSTAR_HEIGHT 8 + #define DOTSTAR_DATA 10 // Example: GP12, adjust to your wiring + #define DOTSTAR_CLK 9 // Example: GP13, adjust to your wiring -// DotStar HD 8x8 Grid settings -#define DOTSTAR_WIDTH 8 -#define DOTSTAR_HEIGHT 8 -#define DOTSTAR_DATA 6 // Example GPIO for DotStar data -#define DOTSTAR_CLK 7 // Example GPIO for DotStar clock - -// ============ I2C BUS OBJECTS ============ -TwoWire PublicI2C = TwoWire(0); // I2C0 (slave) -TwoWire LocalI2C = TwoWire(1); // I2C1 (master) + #define ONBOARD_RGB_LED 48 // Onboard WS2812 RGB LED on GP48 // ============ DEVICE OBJECTS ============= -Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &LocalI2C, OLED_RESET); -// Use a SparkFun_APDS9960 library that supports TwoWire -SparkFun_APDS9960 apds(&LocalI2C); -CRGB leds[NUM_LEDS]; -Adafruit_DotStarMatrix dotstar = Adafruit_DotStarMatrix( - DOTSTAR_WIDTH, DOTSTAR_HEIGHT, DOTSTAR_DATA, DOTSTAR_CLK, - DS_MATRIX_TOP + DS_MATRIX_LEFT + DS_MATRIX_ROWS + DS_MATRIX_PROGRESSIVE, - DOTSTAR_BRG -); -// ============ DATA STRUCTURES ============ -struct SensorData { - int8_t joystickDir; // -1=none, 0=up, 1=down, 2=left, 3=right - bool joystickBtn; - uint16_t colorR, colorG, colorB, colorC; -}; -volatile SensorData latestData; + Adafruit_SSD1306 display(128, 64, &Wire, -1); + CRGB leds[NUM_LEDS]; -// ============ I2C SLAVE DATA HANDLERS ========= -void receiveEvent(int numBytes) { - // Not used in this application, but required by Wire -} + Adafruit_DotStarMatrix dotstar = Adafruit_DotStarMatrix( + DOTSTAR_WIDTH, DOTSTAR_HEIGHT, DOTSTAR_DATA, DOTSTAR_CLK, + DS_MATRIX_TOP + DS_MATRIX_LEFT + DS_MATRIX_ROWS + DS_MATRIX_PROGRESSIVE, + DOTSTAR_BRG + ); -void requestEvent() { - // Copy volatile to local to avoid race conditions - SensorData copy; - noInterrupts(); - copy = latestData; - interrupts(); - // Send as a binary buffer - PublicI2C.write((uint8_t*)©, sizeof(SensorData)); -} +// ============ I2C SCAN FUNCTION ========= -// ============ JOYSTICK INTERPRETATION ========= -#define JOY_THRESHOLD_HIGH 3000 -#define JOY_THRESHOLD_LOW 1000 - -void updateJoystick(SensorData &data) { - int joyX = analogRead(JOY_X_PIN); - int joyY = analogRead(JOY_Y_PIN); - bool joyBtn = digitalRead(JOY_BTN_PIN) == LOW; - - // Default: no direction - data.joystickDir = -1; - - if (joyY > JOY_THRESHOLD_HIGH) data.joystickDir = 0; // Up - else if (joyY < JOY_THRESHOLD_LOW) data.joystickDir = 1; // Down - else if (joyX < JOY_THRESHOLD_LOW) data.joystickDir = 2; // Left - else if (joyX > JOY_THRESHOLD_HIGH) data.joystickDir = 3; // Right - - data.joystickBtn = joyBtn; -} - -// ============ COLOR SENSOR READING ========= -void updateColorSensor(SensorData &data) { - uint16_t r=0, g=0, b=0, c=0; - if (apds.readAmbientLight(c) && - apds.readRedLight(r) && - apds.readGreenLight(g) && - apds.readBlueLight(b)) { - data.colorR = r; - data.colorG = g; - data.colorB = b; - data.colorC = c; + void scanI2CDevices(TwoWire &bus) { + byte error, address; + int nDevices = 0; + Serial.println("Scanning..."); + for (address = 1; address < 127; address++) { + bus.beginTransmission(address); + error = bus.endTransmission(); + if (error == 0) { + Serial.print("I2C device found at address 0x"); + if (address < 16) Serial.print("0"); + Serial.println(address, HEX); + nDevices++; + } + delay(1); + } + if (nDevices > 0) { + Serial.println("done"); + } } -} -// ============ DISPLAY LOGIC ========= -void updateDisplays(const SensorData &data) { - // DotStar: show direction as arrow or color as background - dotstar.fillScreen(0); - if (data.joystickDir == 0) dotstar.drawPixel(3, 0, dotstar.Color(0,0,255)); // Up - else if (data.joystickDir == 1) dotstar.drawPixel(3, 7, dotstar.Color(0,0,255)); // Down - else if (data.joystickDir == 2) dotstar.drawPixel(0, 3, dotstar.Color(0,0,255)); // Left - else if (data.joystickDir == 3) dotstar.drawPixel(7, 3, dotstar.Color(0,0,255)); // Right - else dotstar.fillScreen(dotstar.Color(data.colorR>>2, data.colorG>>2, data.colorB>>2)); // Show color - dotstar.show(); +// ============ ONBOARD RGB LED TEST ========= - // FastLED: color bar with button brightness - uint8_t brightness = data.joystickBtn ? 255 : 64; - for (int i = 0; i < NUM_LEDS; i++) { - leds[i] = CRGB(data.colorR>>4, data.colorG>>4, data.colorB>>4); - leds[i].nscale8_video(brightness); + void testOnboardRGB() { + // Note: Onboard RGB LED is a WS2812 on GP48 + FastLED.addLeds(leds, 1); // Use just 1 LED + leds[0] = CRGB::Red; + FastLED.show(); + delay(500); + leds[0] = CRGB::Blue; + FastLED.show(); + delay(500); + leds[0] = CRGB::Green; + FastLED.show(); + delay(500); + FastLED.clear(); + FastLED.show(); + FastLED.clear(true); // Clear LED data and reset FastLED for main NeoPixel strip } - FastLED.show(); - // OLED: show values - display.clearDisplay(); - display.setCursor(0,0); - display.print("Dir: "); - switch (data.joystickDir) { - case 0: display.println("Up"); break; - case 1: display.println("Down"); break; - case 2: display.println("Left"); break; - case 3: display.println("Right"); break; - default: display.println("None"); break; - } - display.print("Btn: "); display.println(data.joystickBtn ? "Pressed" : "Released"); - display.print("R: "); display.println(data.colorR); - display.print("G: "); display.println(data.colorG); - display.print("B: "); display.println(data.colorB); - display.print("C: "); display.println(data.colorC); - display.display(); -} +// ============ SYSTEM TEST ========= -// ============ SETUP FUNCTION ============= -void setup() { - Serial.begin(115200); + void runSystemTest() { - // --- Initialize PublicI2C as Slave --- - PublicI2C.begin(PUBLIC_I2C_ADDR, PUBLIC_I2C_SDA, PUBLIC_I2C_SCL, 100000); - PublicI2C.onReceive(receiveEvent); - PublicI2C.onRequest(requestEvent); - Serial.println("PublicI2C (slave) initialized."); + Serial.println("\n===== SYSTEM TEST =====\n"); - // --- Initialize LocalI2C as Master --- - LocalI2C.begin(LOCAL_I2C_SDA, LOCAL_I2C_SCL, 100000); - Serial.println("LocalI2C (master) initialized."); + // --- Onboard RGB LED Test --- - // --- Initialize OLED Display --- - if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { - Serial.println("SSD1306 allocation failed"); - while (1); - } - display.clearDisplay(); - display.setTextSize(1); - display.setTextColor(SSD1306_WHITE); - display.setCursor(0,0); - display.println("OLED Ready!"); - display.display(); + Serial.println("Testing onboard RGB LED..."); + testOnboardRGB(); + Serial.println("Onboard RGB LED: OK"); - // --- Initialize APDS-9960 (SparkFun) --- - if (!apds.init()) { // Uses LocalI2C if library supports it - Serial.println("APDS-9960 initialization failed"); - display.println("No APDS-9960!"); + // --- Joystick Test --- + + int joyX = analogRead(JOY_X_PIN); + int joyY = analogRead(JOY_Y_PIN); + int joyBtn = digitalRead(JOY_BTN_PIN); + Serial.print("Joystick X: "); Serial.println(joyX); + Serial.print("Joystick Y: "); Serial.println(joyY); + Serial.print("Button: "); Serial.println(joyBtn ? "Released" : "Pressed"); + Serial.println("Joystick: OK"); + + // --- I2C Device Scan --- + + Serial.println("Scanning I2C devices..."); + scanI2CDevices(Wire); + + // --- OLED Test --- + + if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { + Serial.println("OLED: FAIL"); + while(1); + } + + display.clearDisplay(); + display.setTextSize(1); + display.setTextColor(SSD1306_WHITE); + display.setCursor(0,0); + display.println("SYSTEM TEST"); + display.println("Joystick OK"); + display.println("I2C OK"); + display.println("FastLED OK"); + display.println("DotStar OK"); display.display(); - while (1); + Serial.println("OLED: OK"); + + // --- FastLED (NeoPixel) Test --- + + FastLED.addLeds(leds, NUM_LEDS); + + for (int i = 0; i < NUM_LEDS; i++) { + leds[i] = CRGB(0, 255, 0); // Green + } + FastLED.show(); + delay(1000); + FastLED.clear(); + FastLED.show(); + Serial.println("FastLED: OK"); + + // --- DotStar (APA102) Test --- + + dotstar.begin(); + dotstar.setBrightness(32); + dotstar.fillScreen(dotstar.Color(255, 0, 0)); // Red + dotstar.show(); + delay(1000); + dotstar.fillScreen(0); + dotstar.show(); + Serial.println("DotStar: OK"); + + Serial.println("===== SYSTEM TEST COMPLETE ====="); } - display.println("APDS-9960 ready!"); - display.display(); - // Enable color sensing - apds.enableLightSensor(false); +// ============ SETUP ============= - // --- Initialize Joystick Pins --- - pinMode(JOY_BTN_PIN, INPUT_PULLUP); // Button is active LOW + void setup() { - // --- Initialize FastLED (NeoPixel) --- - FastLED.addLeds(leds, NUM_LEDS); - FastLED.clear(); - FastLED.show(); + Serial.begin(115200); - // --- Initialize DotStar Matrix --- - dotstar.begin(); - dotstar.setBrightness(32); // Adjust as needed - dotstar.fillScreen(0); - dotstar.show(); -} + while(!Serial) { delay(10); } -// ============ MAIN LOOP ================== -void loop() { - SensorData tempData; - updateJoystick(tempData); - updateColorSensor(tempData); + // Initialize I2C + Wire.begin(LOCAL_I2C_SDA, LOCAL_I2C_SCL, 100000); - // Copy to shared struct for I2C - noInterrupts(); - latestData = tempData; - interrupts(); + // Initialize joystick button + pinMode(JOY_BTN_PIN, INPUT_PULLUP); - updateDisplays(tempData); + // Run system test + runSystemTest(); - delay(50); // Adjust as needed -} \ No newline at end of file + // Keep the loop empty as recommended for ESP32-S3 Super Mini + while(true) {} + } + +// ============ LOOP ============= + + void loop() { + // Leave empty to avoid crashes on ESP32-S3 Super Mini + } \ No newline at end of file