347 lines
9.1 KiB
C++
347 lines
9.1 KiB
C++
//======================================================
|
|
// REACTION GAME MAIN ROUTINE
|
|
//======================================================
|
|
|
|
/* This Game Can Be Called From
|
|
* Stand Alone Mode / Bluetooth Connection
|
|
* The primary mode is the standalone but
|
|
* if the bluetooth is connected it has the priority
|
|
* so it will take over the control of the device
|
|
*
|
|
* If you want to control the game via bluetooth
|
|
* you need to call : game_reaction_bluetooth(JSON String)
|
|
* If you want to use the stand alone mode
|
|
* you need to call : game_reaction_standalone()
|
|
*
|
|
* the game returns a float point number which is
|
|
* in seconds. so the athlete know how long he takes to react
|
|
*/
|
|
|
|
//------------------------------------------------------
|
|
// Request From Stand Alone Buttons
|
|
//------------------------------------------------------
|
|
|
|
void game_reaction_standalone()
|
|
{
|
|
// Variables
|
|
uint8_t minDelay = 1;
|
|
uint8_t maxDelay = 3;
|
|
uint8_t trials = 10;
|
|
|
|
// Call the Game Play
|
|
play_reaction(minDelay, maxDelay, trials);
|
|
|
|
// Give Permision To Change Display
|
|
DISPLAY_CHANGED = false;
|
|
}
|
|
|
|
//------------------------------------------------------
|
|
// Request From Bluetooth Via JSON
|
|
//------------------------------------------------------
|
|
|
|
/* REACTION GAME SETTINGS PARAMETERS NOTE:
|
|
* ------------------------------------------
|
|
*
|
|
* FORMAT :
|
|
* --------
|
|
* {"tr": 10, "mn": 1, "mx": 2}
|
|
*
|
|
* MEANNING :
|
|
* ----------
|
|
* tr : trials pre counter
|
|
* mn : minimum delay, between trials
|
|
* mx : maximum delay, between trials
|
|
*
|
|
* THINGS THAT ENDS THE GAME :
|
|
* ---------------------------
|
|
* 1. BY COUNT DOWN "tr" REACH TO ZERO
|
|
* 2. BY A COMMAND "FROM APP VIA BLUETOOTH"
|
|
*
|
|
* CALCULATING RESULTS :
|
|
* ---------------------
|
|
* Rapid Kick Speed = Number Of Kickes Made / Elasped Time In Sec
|
|
*/
|
|
|
|
void game_reaction_bluetooth(String settings)
|
|
{
|
|
//------------------------------------------------------
|
|
// START OF READING THE SETTINGS
|
|
//------------------------------------------------------
|
|
|
|
// Deserialize the JSON document
|
|
DeserializationError error = deserializeJson(JSON, settings);
|
|
|
|
// JSON ERROR
|
|
if(error) {
|
|
dualcomm(JSON_ERROR);
|
|
return;
|
|
}
|
|
|
|
// PUBLIC VARIABLES
|
|
uint8_t minDelay = JSON["mn"];
|
|
uint8_t maxDelay = JSON["mx"];
|
|
uint16_t trials = JSON["lm"];
|
|
|
|
// Fix Random Error
|
|
maxDelay += 1;
|
|
|
|
// Clearing Buffer
|
|
JSON.clear();
|
|
|
|
// Play The Game
|
|
play_reaction(minDelay, maxDelay, trials);
|
|
|
|
// Give Permision To Change Display
|
|
DISPLAY_CHANGED = false;
|
|
}
|
|
|
|
//------------------------------------------------------
|
|
// Play The Game
|
|
//------------------------------------------------------
|
|
|
|
void play_reaction(uint8_t minDelay, uint8_t maxDelay, uint16_t trials)
|
|
{
|
|
// PUBLIC VARIABLES
|
|
double totalRes = 0.0;
|
|
|
|
// Fix Random Error
|
|
maxDelay += 1;
|
|
|
|
// Clearing Buffer
|
|
JSON.clear();
|
|
|
|
//------------------------------------------------------
|
|
// PREPARE FOR GAME START
|
|
//------------------------------------------------------
|
|
|
|
// DisJSON Welcome Message
|
|
terminal("");
|
|
terminal("trials : " + String(trials) + " Strikes");
|
|
terminal("minDelay : " + String(minDelay) + " Seconds");
|
|
terminal("maxDelay : " + String(maxDelay) + " Seconds");
|
|
terminal("2 Seconds To Start Get Ready & Good Luck !!");
|
|
terminal("");
|
|
|
|
// Main Variables
|
|
uint16_t sdelay = 0;
|
|
uint16_t power = 0;
|
|
uint16_t response = 0;
|
|
unsigned long startTime = 0;
|
|
unsigned long stopTime = 0;
|
|
|
|
// Ready Signal
|
|
//LED_SIGNAL_REACTION_START();
|
|
|
|
// Display On OLED
|
|
GAME_REACTION_DISPLAY(0, 0);
|
|
|
|
//-------------------------
|
|
// PREPARE FOR GAME START
|
|
//-------------------------
|
|
|
|
// Processing Results
|
|
for(int i=0; i<trials; i++)
|
|
{
|
|
// Reading Kick JSON
|
|
terminal(" ------ Trial Number (" + String(i + 1) + ") ------");
|
|
terminal(" -> Get Ready !!");
|
|
|
|
// Set Random Delay Time
|
|
sdelay = random(minDelay, maxDelay);
|
|
sdelay *= 1000;
|
|
delay(sdelay);
|
|
|
|
// Light Up Green
|
|
//LED_SET_COLOR(0, 255, 0, 255);
|
|
|
|
// Start Timer
|
|
startTime = millis();
|
|
|
|
// Sensing Strike Power
|
|
while(power < VTH)
|
|
{
|
|
// Reading The Strike
|
|
power = PIEZO_MAP;
|
|
|
|
// If Stop Command Came From Smart Phone
|
|
if(isBluetooth)
|
|
{
|
|
String msg = Bluetooth.readStringUntil('\n');
|
|
flushBluetooth;
|
|
msg.trim();
|
|
if(msg == CM_STOP) {
|
|
dualcomm(GAME_OVER);
|
|
// LightUp
|
|
//LED_SIGNAL_END();
|
|
// RESET
|
|
return;
|
|
}
|
|
else if(msg == CM_RESET) {
|
|
//LED_SIGNAL_REACTION_RESET();
|
|
i = 0;
|
|
sdelay = 0;
|
|
power = 0;
|
|
response = 0;
|
|
startTime = millis();
|
|
stopTime = millis();
|
|
totalRes = 0;
|
|
DISPLAY_CHANGED = false;
|
|
GAME_REACTION_DISPLAY(i, response);
|
|
//break;
|
|
}
|
|
}
|
|
|
|
// Reset The Counter
|
|
if(BTN_INCREASE.pressed()) {
|
|
//LED_SIGNAL_REACTION_RESET();
|
|
i = 0;
|
|
sdelay = 0;
|
|
power = 0;
|
|
response = 0;
|
|
startTime = millis();
|
|
stopTime = millis();
|
|
totalRes = 0;
|
|
DISPLAY_CHANGED = false;
|
|
GAME_REACTION_DISPLAY(i, response);
|
|
}
|
|
|
|
// Will Exit The Game
|
|
if(BTN_CENTER.pressed()) {
|
|
dualcomm(GAME_OVER);
|
|
DISPLAY_CHANGED = false;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Stop Timer
|
|
stopTime = millis();
|
|
|
|
// Stop Light
|
|
//LED_SET_COLOR(255, 0, 0, 255);
|
|
|
|
// Calculating Response Time
|
|
response = stopTime - startTime - 1;
|
|
totalRes = totalRes + ((float)response/1000);
|
|
|
|
// Create Json JSON
|
|
String msg = reaction_JSON_json(i+1, power, response, sdelay);
|
|
|
|
// Display On OLED
|
|
GAME_REACTION_DISPLAY(i+1, response);
|
|
|
|
// Print To Terminal
|
|
dualcomm(msg);
|
|
|
|
// Clear All
|
|
sdelay = 0;
|
|
power = 0;
|
|
response = 0;
|
|
}
|
|
|
|
// Red Light Delay
|
|
delay(500);
|
|
|
|
// END GAME
|
|
dualcomm(GAME_OVER);
|
|
|
|
// Blink Red
|
|
//LED_SIGNAL_CELEBRATION();
|
|
|
|
// Display Result
|
|
GAME_REACTION_RESULT(trials, totalRes);
|
|
|
|
// Return To Game Selector
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------
|
|
// REACTION JSON -> To Send Back To Mobile Device
|
|
//------------------------------------------------------
|
|
|
|
String reaction_JSON_json(unsigned int count, unsigned int power, unsigned int response, unsigned int startDelay)
|
|
{
|
|
// Convert To Seconds Unit
|
|
float re = response;
|
|
re /= 1000;
|
|
|
|
// Asignning Values
|
|
JSON["ct"] = count; // Strike Number
|
|
JSON["pw"] = power; // Strike Power In Analog Read
|
|
JSON["sd"] = startDelay/1000; // LED Strip Start Delay in Seconds
|
|
JSON["re"] = String(re, 3).toFloat(); // Strike Reaction Time In Milli Sec
|
|
|
|
String output;
|
|
serializeJson(JSON, output);
|
|
JSON.clear();
|
|
return output;
|
|
}
|
|
|
|
//------------------------------------------------------
|
|
// REACTION GAME START LED SIGNAL
|
|
//------------------------------------------------------
|
|
|
|
void LED_SIGNAL_REACTION_START()
|
|
{
|
|
// Cross fade the white signal to get ready
|
|
//LED_CROSS_FADE(255, 255, 255, 3);
|
|
|
|
// Set the LED strip color to red
|
|
//LED_SET_COLOR(255, 0, 0, 255);
|
|
}
|
|
|
|
//------------------------------------------------------
|
|
// REACTION GAME RESET LED SIGNAL
|
|
//------------------------------------------------------
|
|
|
|
void LED_SIGNAL_REACTION_RESET()
|
|
{
|
|
// Light Bright Blue
|
|
//LED_BLINK(0, 0, 255, 2);
|
|
|
|
// Wait For 1/4 Second
|
|
//delay(250);
|
|
|
|
// Fade Out The Blue
|
|
//LED_SET_COLOR(0, 255, 0, 255);
|
|
}
|
|
|
|
//------------------------------------------------------
|
|
// OLED GAME PLAY REACTION
|
|
//------------------------------------------------------
|
|
|
|
void GAME_REACTION_DISPLAY(uint16_t count, float reatime)
|
|
{
|
|
OLED_CLEAR();
|
|
drawTextCenter(128/2, 0, 2, "KICK : " + String(count));
|
|
drawTextCenter(128/2, 20, 3, "TIME : " + String(((float)reatime/1000), 2));
|
|
|
|
// Exit Button Command Only Via Stand Alone Mode
|
|
if(BLUETOOTH_STATUS == false) {
|
|
drawTextCenter(128/2, 50, 1, "<< EXIT >>");
|
|
}
|
|
|
|
OLED_SHOW();
|
|
}
|
|
|
|
//------------------------------------------------------
|
|
// OLED - GAME TIMEATTACK RESULT
|
|
//------------------------------------------------------
|
|
|
|
void GAME_REACTION_RESULT(uint16_t trials, uint16_t total_reaction)
|
|
{
|
|
OLED_CLEAR();
|
|
float avgReaction = 0.0;
|
|
avgReaction = (float)total_reaction/trials;
|
|
drawTextCenter(128/2, 0, 2, "RESULT");
|
|
drawTextCenter(128/2, 20, 2, String(avgReaction, 3) + " s");
|
|
drawTextCenter(128/2, 50, 1, "<< EXIT >>");
|
|
OLED_SHOW();
|
|
|
|
// Waiting For Center Button To Move On
|
|
while(1){
|
|
if(BTN_CENTER.pressed()) {
|
|
break;
|
|
}
|
|
}
|
|
}
|