371 lines
14 KiB
C++
371 lines
14 KiB
C++
/* ===============================================
|
|
* - 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 <Wire.h>
|
|
#include <EEPROM.h>
|
|
#include <Button.h>
|
|
#include <TimeTrigger.h>
|
|
#include <ArduinoJson.h>
|
|
#include <NeoPixelBus.h>
|
|
#include <BluetoothSerial.h>
|
|
//======================================================
|
|
// 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<NeoGrbFeature, Neo800KbpsMethod> 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;
|
|
}
|
|
}
|
|
}
|