/* =============================================== * - THIS IS TAKEONE ESP32 BOARD - * =============================================== * MPU9250 Address : 0X69 (ADDRESS) * OLED 128x64 Address : 0X3C (ADDRESS) * ----------------------------------------------- * Description : PIN GPIO# * ----------------------------------------------- * NEOPIXEL LED STRIP : A0/GPIO 26 * PIEZO SENSOR : A2/GPIO 34 - ANALOG ONLY INPUT * RANDOM SEED : A3/GPIO 39 - ANALOG ONLY INPUT * BUTTONS : TLB (35), BLB (15), CB (33), BRB (27), TRB(12) * I2C PIN : SDA 21, SCL 22 (DIGITAL) * SPI PIN : CS 5, SCK 18, MISO 19, MOSI 23 (DIGITAL) * BOOST CONTROL PIN : 14 (DIGITAL) OUTPUT ON PADS (TP1 +5V, TP2 GND) * LED PIN : 13 (DIGITAL) * BATTERY MONITOR PIN : 35 (ANALOG) * ----------------------------------------------- * BUTTONS PINOUTS : PIN GPIO * ----------------------------------------------- * TOP LEFT BUTTON : 15 - SWITCH PREVIOUS MENU / CHANGE PARAMETER * TOP RIGHT BUTTON : 12 - SWITCH NEXT MENU / CHANGE PARAMETER * BOTTOM LEFT BUTTON : 32 - POWER INC & BACK & INC PARAMETER * BOTTOM RIGHT BUTTON : 27 - POWER DEC & SAVE & DEC PARAMETER * CENTER BUTTON : 33 - POWER ON & SELECT * ----------------------------------------------- * Exclusive Features Of TAKEONE BOARD * ----------------------------------------------- * ESP32 TAKEONE Board has some unique hardware features * 1. Battery Voltage Level Monitoring Via Analog Pin 35 * 2. Boost Converter In Case We Need 5V Supply From Li-Ion Battery * 3. I2C : Motion Sensor IMU/MPU9250 9 Degrees Of Fredom * 4. SPI : SDCARD Reader */ //====================================================== // LIBRARIES //====================================================== #include #include #include #include #include #include #include //====================================================== // PUBLIC VARIABLES //====================================================== uint8_t MENU_COUNT = 1; bool BLUETOOTH_STATUS = false; bool CHARGE_STATE = false; bool DISPLAY_CHANGED = false; //====================================================== // HARDWARE DEFINITIONS //====================================================== // Nessesary Definition For Bluetooth Library #if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED) #error Bluetooth is not enabled! Please run `make menuconfig` to and enable it #endif //------------------------------------------------------ // Serial Terminal //------------------------------------------------------ #define Terminal Serial // SERIAL PORT USED AS TERMINAL WINDO FOR DEBUG #define isTerminal Terminal.available() // Terminal Serial Buffer Available #define flushTerminal while(isTerminal) { Terminal.read(); } //------------------------------------------------------ // Bluetooth Terminal //------------------------------------------------------ BluetoothSerial Bluetooth; // Here We Use the Native Bluetooth In The ESP32 #define isBluetooth Bluetooth.available() // Bluetooth Serial Buffer Available #define flushBluetooth while(isBluetooth) { Bluetooth.read(); } //------------------------------------------------------ // Buttons //------------------------------------------------------ Button BTN_PREVIOUS(15); // TL : 15 - SWITCH PREVIOUS MENU / CHANGE PARAMETER Button BTN_NEXT(12); // TR : 12 - SWITCH NEXT MENU / CHANGE PARAMETER Button BTN_CENTER(33); // CT : 33 - POWER INC & BACK & INC PARAMETER Button BTN_INCREASE(32); // BL : 32 - POWER DEC & SAVE & DEC PARAMETER Button BTN_DECREASE(27); // BR : 27 - POWER ON & SELECT //------------------------------------------------------ // Boost 3V3 To 5V //------------------------------------------------------ #define BOOST_PIN 14 #define BOOST_SETUP pinMode(BOOST_PIN, OUTPUT) #define BOOST_ON digitalWrite(BOOST_PIN, HIGH) #define BOOST_OFF digitalWrite(BOOST_PIN, LOW) #define BOOST_STU digitalRead(BOOST_PIN) //------------------------------------------------------ // Keep Power On //------------------------------------------------------ #define POWER_PIN 13 #define POWER_SETUP pinMode(POWER_PIN, OUTPUT) #define POWER_OFF digitalWrite(POWER_PIN, LOW) #define POWER_ON digitalWrite(POWER_PIN, HIGH) TimeTrigger POWER_PRESS(4000); // The Interval In mSeconds //------------------------------------------------------ // Piezo Transducer //------------------------------------------------------ #define VTH 15 // THRESHOLD VOLTAGE FOR ZERO POSITIONNING KICKING POWER SENSOR #define PIEZO_PIN 34 // IMPACT SENSOR #define RANDOM_SOURCE 39 // RANDOM NUMBER GENERATOR SOURCE #define PIEZO_READ analogRead(PIEZO_PIN) #define PIEZO_MAP map(PIEZO_READ, VTH, 4095, 0, 100) //------------------------------------------------------ // Battery Level Monitoring //------------------------------------------------------ #define BATTERY_PIN 35 #define BATTERY (float)(((analogRead(BATTERY_PIN) * (3.3 / 4096)) * 2) + 0.31) #define CHARGE round(mapf(BATTERY, 3.27, 4.31, 0, 100), 1) //------------------------------------------------------ // Power Charging Status //------------------------------------------------------ #define STAT_PIN 25 #define STAT_SETUP pinMode(STAT_PIN, INPUT) #define STAT_READ digitalRead(STAT_PIN) //------------------------------------------------------ // Neo Pixel LED Strip //------------------------------------------------------ #define PIXEL_COUNT 21 // make sure to set this to the number of pixels in your strip #define PIXEL_PIN 26 // make sure to set this to the correct pin, ignored for Esp8266 // three element pixels, in different order and speeds NeoPixelBus PIXEL_STRIP(PIXEL_COUNT, PIXEL_PIN); //------------------------------------------------------ // JSON Object & Memory //------------------------------------------------------ #define CAPACITY 200 DynamicJsonDocument JSON(CAPACITY); // Building JSON Buffer // FIXED OPERATION MODE MESSAGES ~~~~~~~~~~~~~~~~~~~~~~ #define BLUETOOTH_START "{\"status\":\"BLUETOOTH STARTED\"}" #define BLUETOOTH_FAIL "{\"status\":\"BLUETOOTH FAILED\"}" #define BLUETOOTH_CONNECTED "{\"status\":\"BLUETOOTH CONNECTED\"}" #define BLUETOOTH_DISCONNECTED "{\"status\":\"BLUETOOTH DISCONNECTED\"}" #define STAND_ALONE_MODE "{\"status\":\"STAND ALONE MODE\"}" // FIXED MESSAGES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #define POWERUP "{\"status\":\"POWER UP\"}" #define POWEROFF "{\"status\":\"POWER OFF\"}" #define UNDERSTOOD "{\"status\":\"OK\"}" #define JSON_ERROR "{\"status\":\"ERROR JSON\"}" #define TARGET_MET "{\"status\":\"TARGET MEET\"}" #define GAME_OVER "{\"status\":\"GAME OVER\"}" #define TIME_OVER "{\"status\":\"TIME OVER\"}" #define UNKNOWN_GAME "{\"status\":\"UNKNOWN GAME\"}" // GAME NAMES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #define GM_COUNTER "{\"gm\":\"COUNTER\"}" #define GM_TATTACK "{\"gm\":\"TIME ATTACK\"}" #define GM_REACTION "{\"gm\":\"REACTION\"}" #define GM_DECISION "{\"gm\":\"DECISION\"}" #define GM_STAMINA "{\"gm\":\"STAMINA\"}" // COMMAND LIST ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #define CM_START "{\"cm\":\"START\"}" #define CM_RESET "{\"cm\":\"RESET\"}" #define CM_STOP "{\"cm\":\"STOP\"}" #define CM_EXIT "{\"cm\":\"EXIT\"}" //====================================================== // MAIN SETUP //====================================================== void setup() { // Power Hold POWER_SETUP; POWER_ON; // Turn On Booster BOOST_SETUP; BOOST_OFF; // Charging Status Pin STAT_SETUP; // I2C Module & OLED Wire.begin(); delay(5); OLED_INIT(); OLED_CLEAR(); OLED_SHOW(); // Start Buttons Function BTN_PREVIOUS.begin(); BTN_NEXT.begin(); BTN_CENTER.begin(); BTN_INCREASE.begin(); BTN_DECREASE.begin(); // Communication Ports Terminal.begin(9600); Terminal.println(); // To Detect Connection / Disconnection Event Bluetooth.register_callback(callback); // Starting Bluetooth Wireless With Name (KICKER) if(!Bluetooth.begin("KICKER")) { terminal(POWERUP); terminal(BLUETOOTH_FAIL); } else { dualcomm(POWERUP); dualcomm(BLUETOOTH_START); } // The Random Number Source randomSeed(analogRead(RANDOM_SOURCE)); // Display Welcome Screen KICKER_LOGO(); delay(2000); } //====================================================== // MAIN PROGRAM LOOP //====================================================== void loop() { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // This Is For Bluetooth Mode //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if(BLUETOOTH_STATUS == true) { // Initialization Of Bluetooth Connected Mode OLED_BLUETOOTH_MODE(); // Display Bluetooth Connected Mode DISPLAY_CHANGED = false; // Give Permition To Change The Content delay(3000); // Hold The Display Content For 3 Seconds // While You Are On Bluetooth Connected Mode while(BLUETOOTH_STATUS == true) { ListenToBluetooth(); // Reading Only From Bluetooth } // Give Permition To Change The Content DISPLAY_CHANGED = false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // This Is For Stand Alone Mode //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ else { // Initialization Of Stand Alone Mode OLED_STANDALONE_MODE(); // Display Stand Alone Mode DISPLAY_CHANGED = false; // Give Permition To Change The Content delay(3000); // Hold The Display Content For 3 Seconds // While You Are On Stand Alone Mode while(BLUETOOTH_STATUS == false) { ListenToStandAlone(); // Enter Listen To Stand Alone Buttons } // Once The Stand Alone Mode Is Over DISPLAY_CHANGED = false; // Give Permition To Change The Display } } //------------------------------------------------------ // LISTEN TO BLUETOOTH //------------------------------------------------------ void ListenToBluetooth() { if(isBluetooth) { // Reading Message From Bluetooth String msg = Bluetooth.readStringUntil('\n'); flushBluetooth; msg.trim(); // Display On Serial Monitor For Debuging terminal(msg); // If It Was A Command To Power OFf if(msg == POWEROFF) { OLED_POWERING_DOWN(); } // Deserialize the JSON document DeserializationError error = deserializeJson(JSON, msg); // If The System Understood The Message Clearly if(!error) { // Sending Status Message dualcomm(UNDERSTOOD); // Reading Game Name & Settings String game = JSON["gm"]; String settings = JSON["set"]; // Clearing JSON Buffer JSON.clear(); // Entering To Game Selector bluetooth_game_selector(game, settings); } else { terminal(JSON_ERROR); } } } //------------------------------------------------------ // LISTEN TO STAND ALONE //------------------------------------------------------ void ListenToStandAlone() { // SHIFT TO PREVIOUS GAME MENU if(BTN_PREVIOUS.pressed()) { // Checking The Condition Of Order Number if(MENU_COUNT == 1 || MENU_COUNT < 1) { MENU_COUNT = 3; // If The Value Equals To Zero Then Roll Back To 4 } else { MENU_COUNT -= 1; } // Give Permition To Change The Screen DISPLAY_CHANGED = false; } // SHIFT TO NEXT GAME MENU else if(BTN_NEXT.pressed()) { // Checking The Condition Of Order Number if(MENU_COUNT == 3 || MENU_COUNT > 3) { MENU_COUNT = 1; // If The Value Exceeds 4 Then Roll Back To 1 } else { MENU_COUNT += 1; } // Give Permition To Change The Screen DISPLAY_CHANGED = false; } // SELECT CURRENT DISPLAYED MENU else if(BTN_CENTER.pressed()) { // IF LONG PRESS -> POWER OFF KICKER DETECT_LONG_PRESS(); // IF SHORT PRESS -> PLAY GAME CORESPONDING TO NUMBER switch(MENU_COUNT) { case 1: // Play Counter Game Terminal.println("SELECTED -> GAME COUNTER"); game_counter_standalone(); break; case 2: // Play Time Attack Game Terminal.println("SELECTED -> GAME TIME ATTACK"); time_attack_standalone(); break; case 3: // Play Reaction Game Terminal.println("SELECTED -> GAME REACTION"); game_reaction_standalone(); break; } } // Display The Game Pages if(DISPLAY_CHANGED == false) { // IF Previous / Next Buttons Are Pressed -> Display Menu Selection On Terminal switch(MENU_COUNT) { case 1: // Play Counter Game //Terminal.println("MENU #" + String(MENU_COUNT) + " - " + "GAME COUNTER"); GAME_TITLE_DISPLAY(MENU_COUNT, "COUNTER"); break; case 2: // Play Time Attack Game //Terminal.println("MENU #" + String(MENU_COUNT) + " - " + "GAME TIME ATTACK"); GAME_TITLE_DISPLAY(MENU_COUNT, "TIME ATTACK"); break; case 3: // Play Reaction Game //Terminal.println("MENU #" + String(MENU_COUNT) + " - " + "GAME REACTION"); GAME_TITLE_DISPLAY(MENU_COUNT, "REACTION"); break; } } }