Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2f2b6af671 | ||
|
dff282567d | ||
|
59215f4d38 | ||
|
1c59afa216 |
2
INSTALL
2
INSTALL
@ -63,6 +63,8 @@ Installing the basic Fun with Binary in offline mode is relatively easy.
|
||||
4. Minify the script.js with http://lisperator.net/uglifyjs/ and replace the
|
||||
line after <!-- JS --> in the index.html with the result inside the tags
|
||||
<script>*result*</script>
|
||||
Note: If you have problems minifying try replacing `let` by `var`, then
|
||||
minify, and then reverting the replace in the minified version.
|
||||
|
||||
5. Make the resulting HTM usable with the following tool:
|
||||
https://github.com/CytronTechnologies/ESP8266-WiFi-Module/raw/master/convertHtml/convertHtml.jar
|
||||
|
25
README.md
25
README.md
@ -25,7 +25,15 @@ There are no special prerequisites for the offline mode.
|
||||
|
||||
At least: Arduino Uno with ESP8266-01, 6 leds (and 6 resistors), wires, breadboard.
|
||||
|
||||
Some instruction of how to build it can be found on my blog post about this project: [https://blog.diogo.site/posts/fun-with-binary](https://blog.diogo.site/posts/fun-with-binary)
|
||||
You have instructions of how to build your own FwB in my blog: [https://blog.diogo.site/posts/fun-with-binary](https://blog.diogo.site/posts/fun-with-binary)
|
||||
|
||||
## MostraUP edition
|
||||
This is a special edition that adds a password mechanism to force single player
|
||||
in online mode.
|
||||
Every output messages were translated to Portuguese due to
|
||||
University of Porto's Exhibition (MostraUP) being a portuguese event.
|
||||
For regular usage (during a lecture) you will probably find standard release 2.0
|
||||
a better option: https://www.diogo.site/projects/fun_with_binary#releases
|
||||
|
||||
## Versioning
|
||||
|
||||
@ -63,18 +71,3 @@ Additional library software has been made available. All of it is Free Software
|
||||
and can be distributed under liberal terms, but those terms may differ in detail
|
||||
from the AGPL's particulars. See each package's license file in their official
|
||||
repository for additional terms.
|
||||
|
||||
## New this version
|
||||
|
||||
This is version 2.0 of Fun with Binary and includes the following (key) changes
|
||||
from the previous one:
|
||||
|
||||
- Client <-> Server <-> Arduino was replaced by a Client <-> Arduino structure
|
||||
- ESP8266 is now required for Access Point purposes
|
||||
- Both modes have become PHP independent (mostly relevant in the offline one)
|
||||
|
||||
The last release, 2.0, gave us these improvements:
|
||||
|
||||
- Significant visual improvement
|
||||
- 2 Powers Label switch functionality
|
||||
- Offline mode is now lighter and more portable (no computer with webserver required anymore)
|
||||
|
70
auth/index.html
Normal file
70
auth/index.html
Normal file
@ -0,0 +1,70 @@
|
||||
<!--
|
||||
|
||||
Fun with Binary - a fun way of introducing binary
|
||||
Copyright (C) 2018, Diogo Cordeiro.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=800" />
|
||||
<title>Fun with Binary</title>
|
||||
<meta name="description" content="A fun way of introducing binary">
|
||||
<meta name="author" content="Diogo Cordeiro">
|
||||
<!-- CSS -->
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
</head>
|
||||
|
||||
<body class="container">
|
||||
|
||||
<!-- auth_html_message_Busy -->
|
||||
<div id="statement">
|
||||
<p class="text" id="statement_text">
|
||||
Já está alguém a jogar, espera pela tua vez! :)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- auth_html_message_readyToPLay -->
|
||||
<div id="statement">
|
||||
<p class="text" id="statement_text">
|
||||
Acende as lâmpadas conforme a caixa! :)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- auth_html_login_dialog -->
|
||||
<div class="images" id="leds">
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<ul id="settings">
|
||||
<li>
|
||||
<div class="button">
|
||||
<input type="button" onclick="submit_auth_form()" value="Vamos Jogar!" id="play_button">
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Credits -->
|
||||
<p class="text" id="footer">Feito com <span style="color:
|
||||
#e25555;">♥</span> por
|
||||
<a href="https://www.diogo.site/">Diogo Cordeiro</a></p>
|
||||
<!-- JS -->
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
152
auth/script.js
Normal file
152
auth/script.js
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Fun with Binary - a fun way of introducing binary
|
||||
* Copyright (C) 2018, Diogo Cordeiro.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category UI interaction
|
||||
* @package Fun with Binary
|
||||
* @author Diogo Cordeiro <up201705417@fc.up.pt>
|
||||
* @copyright 2018 Diogo Cordeiro.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link https://www.diogo.site/projects/fun_with_binary/
|
||||
*/
|
||||
|
||||
|
||||
/***********************************
|
||||
* EXTEND JAVASCRIPT FUNCTIONALITY *
|
||||
***********************************/
|
||||
|
||||
/**
|
||||
* Returns a random integer between min (inclusive) and max (inclusive)
|
||||
* Using Math.round() would give a non-uniform distribution!
|
||||
*/
|
||||
function getRandomInt (min, max)
|
||||
{
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace char at given position
|
||||
*/
|
||||
String.prototype.replaceAt=function(index, replacement)
|
||||
{
|
||||
return this.substr(0, index) + replacement+ this.substr(index +
|
||||
replacement.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if session storage is available
|
||||
*/
|
||||
function is_session_storage_available ()
|
||||
{
|
||||
return window.sessionStorage != null;
|
||||
}
|
||||
|
||||
//***********************************
|
||||
|
||||
/***********************************
|
||||
* GAME SETTINGS *
|
||||
***********************************/
|
||||
|
||||
// Box IP
|
||||
let URL = "http://42.42.42.42/";
|
||||
|
||||
// Number of leds
|
||||
let NLEDS = 6;
|
||||
|
||||
// ON and OFF leds srcs
|
||||
let LED_OFF = "data:image/png;base64,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";
|
||||
let LED_ON = "data:image/png;base64,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";
|
||||
//***********************************
|
||||
|
||||
|
||||
/**********************************
|
||||
* ACTUAL GAME *
|
||||
**********************************/
|
||||
|
||||
/**
|
||||
* Global variables
|
||||
*/
|
||||
// Empty Answer
|
||||
empty_answer = '';
|
||||
while (empty_answer.length < NLEDS)
|
||||
{
|
||||
empty_answer += '0';
|
||||
}
|
||||
|
||||
// current answer
|
||||
current_answer = empty_answer;
|
||||
|
||||
/**
|
||||
* Create leds
|
||||
*/
|
||||
for (let i = 0; i < NLEDS; ++i)
|
||||
{
|
||||
// Led holder
|
||||
let figure = document.createElement ("figure");
|
||||
figure.setAttribute ("class", "box");
|
||||
|
||||
// Led
|
||||
let img = document.createElement ("img");
|
||||
|
||||
img.src = LED_OFF;
|
||||
img.setAttribute ("value", "OFF");
|
||||
|
||||
img.id = "led" + i;
|
||||
img.setAttribute ("class", "led");
|
||||
img.setAttribute ("onclick", "switch_led("+i+")");
|
||||
figure.appendChild (img);
|
||||
|
||||
document.getElementById("leds").appendChild(figure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn current answer bits accordingly
|
||||
*/
|
||||
function switch_led (led_id)
|
||||
{
|
||||
let image = document.getElementById("led"+led_id);
|
||||
if (image.getAttribute("value") == "ON")
|
||||
{
|
||||
image.setAttribute ("value", "OFF");
|
||||
image.src = LED_OFF;
|
||||
|
||||
current_answer = current_answer.replaceAt(led_id, "0");
|
||||
}
|
||||
else
|
||||
{
|
||||
image.setAttribute ("value", "ON");
|
||||
image.src = LED_ON;
|
||||
|
||||
current_answer = current_answer.replaceAt(led_id, "1");
|
||||
}
|
||||
}
|
||||
|
||||
function submit_auth_form ()
|
||||
{
|
||||
let xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
if (this.responseText == "ok")
|
||||
window.location.replace (URL+"game");
|
||||
else
|
||||
alert (this.responseText);
|
||||
}
|
||||
};
|
||||
xhttp.open("POST", URL+"auth", true);
|
||||
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
sessionStorage.token=getRandomInt (42, 31337)
|
||||
xhttp.send("password="+current_answer+"&token="+sessionStorage.token);
|
||||
}
|
BIN
fun-with-binary-mostraup-production.zip
Normal file
BIN
fun-with-binary-mostraup-production.zip
Normal file
Binary file not shown.
@ -38,9 +38,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<!-- Statement -->
|
||||
<div id="statement">
|
||||
<p class="text" id="statement_text">
|
||||
How do you represent the number
|
||||
Como representas o número
|
||||
<span id="statement_value"></span>
|
||||
in binary?
|
||||
em binário?
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -48,7 +48,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<ul id="settings">
|
||||
<li>
|
||||
<div class="button" id="label_switch_button">
|
||||
<p class="text" id="settings_label_label">Labels</p>
|
||||
<p class="text"
|
||||
id="settings_label_label">Potências de 2</p>
|
||||
<label class="switch">
|
||||
<input id="label_switch"
|
||||
class="toggle"
|
||||
@ -63,7 +64,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
</ul>
|
||||
|
||||
<!-- Credits -->
|
||||
<p class="text" id="footer">Made with <span style="color: #e25555;">♥</span> by
|
||||
<p class="text" id="footer">Feito com <span style="color:
|
||||
#e25555;">♥</span> por
|
||||
<a href="https://www.diogo.site/">Diogo Cordeiro</a></p>
|
||||
<!-- JS -->
|
||||
<script src="script.js"></script>
|
@ -56,12 +56,11 @@ function is_session_storage_available()
|
||||
/***********************************
|
||||
* GAME SETTINGS *
|
||||
***********************************/
|
||||
|
||||
// Online Mode (only used in Online Mode)
|
||||
ONLINEMODE = false;
|
||||
ONLINEMODE = true;
|
||||
|
||||
// Box IP (only used in Online Mode)
|
||||
ONLINEURL = "http://42.42.42.42/";
|
||||
// Box IP
|
||||
ONLINEURL = "http://42.42.42.42/game/";
|
||||
|
||||
// Number of leds
|
||||
NLEDS = 6;
|
||||
@ -87,7 +86,11 @@ LED_ON = "data:image/png;base64,R0lGODlhZAC0ANX/AMDAwP//zP//mf//Zv//M///AP/M///
|
||||
* Global variables
|
||||
*/
|
||||
// Empty Answer
|
||||
for (empty_answer = ''; empty_answer.length < NLEDS; empty_answer += '0');
|
||||
empty_answer = '';
|
||||
while (empty_answer.length < NLEDS)
|
||||
{
|
||||
empty_answer += '0';
|
||||
}
|
||||
|
||||
// correct answer
|
||||
correct_answer = empty_answer;
|
||||
@ -214,9 +217,9 @@ function switch_led(led_id)
|
||||
if (ONLINEMODE)
|
||||
{
|
||||
let xhttp = new XMLHttpRequest();
|
||||
xhttp.open("GET", ONLINEURL+"switch_state?led=" + led_id, true);
|
||||
xhttp.open("GET", ONLINEURL+"switch_state?led=" + led_id +
|
||||
"&token=" + sessionStorage.token, true);
|
||||
xhttp.send();
|
||||
|
||||
}
|
||||
|
||||
// If right answer, finish game, restart a new one
|
||||
@ -333,7 +336,8 @@ function end_game()
|
||||
if (ONLINEMODE)
|
||||
{
|
||||
let xhttp = new XMLHttpRequest();
|
||||
xhttp.open("GET", ONLINEURL+"won", true);
|
||||
xhttp.open("GET", ONLINEURL+"won" +
|
||||
"?token=" + sessionStorage.token, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
82
server/HTML.cpp
Normal file
82
server/HTML.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
#include "HTML.h"
|
||||
|
||||
String cssHTML ()
|
||||
{
|
||||
const String cssHTML =
|
||||
"";
|
||||
|
||||
return cssHTML;
|
||||
}
|
||||
String gameHTML1 ()
|
||||
{
|
||||
const String gameHTML1=
|
||||
"\r\n"
|
||||
"\r\n"
|
||||
"\r\n";
|
||||
|
||||
return gameHTML1;
|
||||
}
|
||||
String gameHTML2 ()
|
||||
{
|
||||
const String gameHTML2=
|
||||
"\r\n"
|
||||
"\r\n"
|
||||
"\r\n";
|
||||
|
||||
return gameHTML2;
|
||||
}
|
||||
String gameHTML3 ()
|
||||
{
|
||||
const String gameHTML3=
|
||||
"\r\n"
|
||||
"\r\n"
|
||||
"\r\n";
|
||||
|
||||
return gameHTML3;
|
||||
}
|
||||
String gameHTML4 ()
|
||||
{
|
||||
const String gameHTML4=
|
||||
"\r\n"
|
||||
"\r\n"
|
||||
"\r\n";
|
||||
|
||||
return gameHTML4;
|
||||
}
|
||||
|
||||
String authHTML1 ()
|
||||
{
|
||||
const String authHTML1=
|
||||
"\r\n"
|
||||
"\r\n"
|
||||
"\r\n";
|
||||
|
||||
return authHTML1;
|
||||
}
|
||||
String authHTML2 ()
|
||||
{
|
||||
const String authHTML2=
|
||||
"\r\n"
|
||||
"\r\n"
|
||||
"\r\n";
|
||||
|
||||
return authHTML2;
|
||||
}
|
||||
String authHTML3 ()
|
||||
{
|
||||
const String authHTML3=
|
||||
"\r\n"
|
||||
"\r\n"
|
||||
"\r\n";
|
||||
|
||||
return authHTML3;
|
||||
}
|
||||
String authHTML4 ()
|
||||
{
|
||||
const String authHTML4=
|
||||
"\r\n"
|
||||
"\r\n"
|
||||
"\r\n";
|
||||
|
||||
return authHTML4;
|
||||
}
|
18
server/HTML.h
Normal file
18
server/HTML.h
Normal file
@ -0,0 +1,18 @@
|
||||
// Due to https://github.com/esp8266/Arduino/issues/3205#issuecomment-299763849
|
||||
|
||||
#ifndef html_h
|
||||
#define html_h
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
String cssHTML ();
|
||||
String gameHTML1 ();
|
||||
String gameHTML2 ();
|
||||
String gameHTML3 ();
|
||||
String gameHTML4 ();
|
||||
String authHTML1 ();
|
||||
String authHTML2 ();
|
||||
String authHTML3 ();
|
||||
String authHTML4 ();
|
||||
|
||||
#endif
|
@ -28,7 +28,7 @@
|
||||
#include <ESP8266WebServer.h>
|
||||
|
||||
// Pages
|
||||
#include "file1.h"
|
||||
#include "HTML.h"
|
||||
|
||||
// Define a dns server for Captive Portal
|
||||
const byte DNS_PORT = 53;
|
||||
@ -40,7 +40,7 @@ IPAddress netMsk(255, 255, 255, 0);
|
||||
|
||||
// These are the WiFi access point settings. Update them to your liking
|
||||
const char *ssid = "Fun with Binary";
|
||||
//const char *password = "";
|
||||
//const char *wifi_password = "";
|
||||
|
||||
// Define a web server at port 80 for HTTP
|
||||
ESP8266WebServer webServer(80);
|
||||
@ -49,11 +49,25 @@ ESP8266WebServer webServer(80);
|
||||
#define NLEDS 6
|
||||
|
||||
// LEDs board outputs
|
||||
int bits[NLEDS] = { D0, D1, D2, D3, D4, D5 };
|
||||
// Orange, Yellow, Green, Blue, Purple, Gray
|
||||
// D0 D1 D2 D5 D6 D7
|
||||
int bits[NLEDS] = { D2, D3, D4, D5, D6, D7 };
|
||||
|
||||
// Memorizes bits state
|
||||
int current_answer[NLEDS] = { 0 };
|
||||
|
||||
// Current state of the game
|
||||
bool is_game_running = false;
|
||||
// Current system password
|
||||
String password = "000000";
|
||||
// Current system token
|
||||
int token = 0;
|
||||
|
||||
// This is an emergency endpoint in case some of students decides to leave
|
||||
// in the middle of a game, you should rename it in production as a security
|
||||
// measure
|
||||
const String FORCERESTARENDPOINT = "force_restart";
|
||||
|
||||
/**
|
||||
* Turns all leds on
|
||||
* **Doesn't update current_answer**
|
||||
@ -86,32 +100,33 @@ turn_all_off()
|
||||
void
|
||||
handleRoot()
|
||||
{
|
||||
|
||||
webServer.send(200, "text/html", file1);
|
||||
webServer.send(200, "text/html",
|
||||
"<meta http-equiv=\"refresh\" content=\"0; url=http://42.42.42.42/auth\" />");
|
||||
}
|
||||
|
||||
/**
|
||||
* 404 - Page Not Found endpoint
|
||||
* Game endpoint
|
||||
*/
|
||||
void
|
||||
handleNotFound()
|
||||
handleGame()
|
||||
{
|
||||
String message = "File Not Found\n\n";
|
||||
message += "URI: ";
|
||||
message += webServer.uri();
|
||||
message += "\nMethod: ";
|
||||
message +=(webServer.method() == HTTP_GET) ? "GET" : "POST";
|
||||
message += "\nArguments: ";
|
||||
message += webServer.args();
|
||||
message += "\n";
|
||||
|
||||
for (uint8_t i = 0; i < webServer.args(); ++i) {
|
||||
message +=
|
||||
" " + webServer.argName(i) + ": " + webServer.arg(i) +
|
||||
"\n";
|
||||
webServer.setContentLength(gameHTML1().length() +
|
||||
gameHTML2().length() +
|
||||
gameHTML3().length() +
|
||||
gameHTML4().length());
|
||||
webServer.send(200, "text/html", gameHTML1());
|
||||
webServer.sendContent(gameHTML2());
|
||||
webServer.sendContent(gameHTML3());
|
||||
webServer.sendContent(gameHTML4());
|
||||
}
|
||||
|
||||
webServer.send(404, "text/plain", message);
|
||||
/**
|
||||
* CSS endpoint
|
||||
*/
|
||||
void
|
||||
return_css()
|
||||
{
|
||||
webServer.send(200, "text/css", cssHTML());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -144,6 +159,78 @@ handleInputError()
|
||||
webServer.send(500, "text/plain", message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Auth endpoint
|
||||
*/
|
||||
void
|
||||
handleAuth()
|
||||
{
|
||||
if (webServer.method() == HTTP_GET)
|
||||
{
|
||||
webServer.setContentLength(authHTML1().length() +
|
||||
authHTML2().length() +
|
||||
authHTML3().length() +
|
||||
authHTML4().length());
|
||||
webServer.send(200, "text/html", authHTML1());
|
||||
webServer.sendContent(authHTML2());
|
||||
webServer.sendContent(authHTML3());
|
||||
webServer.sendContent(authHTML4());
|
||||
}
|
||||
else if (webServer.method() == HTTP_POST)
|
||||
{
|
||||
if (!is_game_running)
|
||||
{
|
||||
if (password == webServer.arg("password"))
|
||||
{
|
||||
is_game_running = true;
|
||||
token = webServer.arg("token").toInt();
|
||||
webServer.send(200, "text/html", "ok");
|
||||
turn_all_off();
|
||||
Serial.print("Current valid token is: ");
|
||||
Serial.println(token);
|
||||
}
|
||||
else
|
||||
{
|
||||
webServer.send(200, "text/html",
|
||||
"Esta palavra-passe está errada.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
webServer.send(200, "text/html",
|
||||
"Já está alguém a jogar, espera pela tua vez! :)");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid HTTP request method
|
||||
handleInputError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 404 - Page Not Found endpoint
|
||||
*/
|
||||
void
|
||||
handleNotFound()
|
||||
{
|
||||
String message = "File Not Found\n\n";
|
||||
message += "URI: ";
|
||||
message += webServer.uri();
|
||||
message += "\nMethod: ";
|
||||
message +=(webServer.method() == HTTP_GET) ? "GET" : "POST";
|
||||
message += "\nArguments: ";
|
||||
message += webServer.args();
|
||||
message += "\n";
|
||||
|
||||
for (uint8_t i = 0; i < webServer.args(); ++i)
|
||||
message +=
|
||||
" " + webServer.argName(i) + ": " + webServer.arg(i) +
|
||||
"\n";
|
||||
|
||||
webServer.send(404, "text/plain", message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches a led state (a.k.a. bit of current answer)
|
||||
*
|
||||
@ -152,27 +239,67 @@ handleInputError()
|
||||
void
|
||||
switch_led()
|
||||
{
|
||||
int incomingByte = webServer.arg("led").toInt();
|
||||
if (!is_game_running || token != webServer.arg("token").toInt())
|
||||
{
|
||||
webServer.send(200, "text/plain", "unauthorized");
|
||||
Serial.print("Invalid token tried to play: ");
|
||||
Serial.println(webServer.arg("token").toInt());
|
||||
return;
|
||||
}
|
||||
|
||||
int incomingByte = webServer.arg("led").toInt();
|
||||
Serial.print("Mandaram-me alterar o estado da lampada: ");
|
||||
Serial.println(incomingByte);
|
||||
|
||||
// Validate input
|
||||
if (incomingByte >= NLEDS || incomingByte < 0)
|
||||
{
|
||||
handleInputError();
|
||||
return;
|
||||
}
|
||||
|
||||
String message = "Led ";
|
||||
|
||||
if (current_answer[incomingByte] == 1)
|
||||
{ // Turn LED off
|
||||
message += incomingByte;
|
||||
message += " off!";
|
||||
digitalWrite(bits[incomingByte], LOW);
|
||||
current_answer[incomingByte] = 0;
|
||||
}
|
||||
else
|
||||
{ // Turn LED on
|
||||
message += incomingByte;
|
||||
message += " on!";
|
||||
digitalWrite(bits[incomingByte], HIGH);
|
||||
current_answer[incomingByte] = 1;
|
||||
}
|
||||
webServer.send(200, "text/plain", message);
|
||||
}
|
||||
|
||||
webServer.send(200, "text/plain", "ok");
|
||||
/**
|
||||
* Generates a binary string password with NLEDS length
|
||||
* Result is stored in global password variable
|
||||
*/
|
||||
void
|
||||
generate_password()
|
||||
{
|
||||
unsigned int dec_password = random(1, pow(2, NLEDS)-1);
|
||||
char tmp_password[] = "000000";
|
||||
for (int i = NLEDS-1; i > 0; --i)
|
||||
{
|
||||
tmp_password[i] =(dec_password & 1) + '0';
|
||||
dec_password >>= 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NLEDS; ++i)
|
||||
{
|
||||
if (tmp_password[i] == '1')
|
||||
{
|
||||
password.setCharAt(i, '1');
|
||||
}
|
||||
}
|
||||
Serial.print("Password is: ");
|
||||
Serial.println(password);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -183,6 +310,8 @@ switch_led()
|
||||
void
|
||||
print_binary_string(String which)
|
||||
{
|
||||
Serial.print("Eu estou a imprimir esta string: ");
|
||||
Serial.println(which);
|
||||
for (int i = 0; i < NLEDS; ++i)
|
||||
{
|
||||
if (which.charAt(i) == '1')
|
||||
@ -208,6 +337,14 @@ reset_game()
|
||||
{
|
||||
current_answer[i] = 0;
|
||||
}
|
||||
|
||||
is_game_running = false;
|
||||
token = 0;
|
||||
|
||||
generate_password();
|
||||
|
||||
// print password
|
||||
print_binary_string(password);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -216,18 +353,32 @@ reset_game()
|
||||
void
|
||||
won_game()
|
||||
{
|
||||
if (!is_game_running || token != webServer.arg("token").toInt())
|
||||
{
|
||||
webServer.send(200, "text/plain", "unauthorized");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
turn_all_off();
|
||||
|
||||
delay(500);
|
||||
|
||||
print_binary_string(current_answer);
|
||||
for (int i = 0; i < NLEDS; ++i)
|
||||
{
|
||||
if (current_answer[i] == 1)
|
||||
{
|
||||
digitalWrite(bits[i], HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
delay(500);
|
||||
}
|
||||
|
||||
reset_game();
|
||||
|
||||
webServer.send(200, "text/plain", "ok");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -252,7 +403,7 @@ setup()
|
||||
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); // subnet FF FF FF 00
|
||||
|
||||
// You can remove/add the password parameter if you want the AP to be open/closed.
|
||||
WiFi.softAP(ssid); //, password);
|
||||
WiFi.softAP(ssid); //, wifi_password);
|
||||
|
||||
// if DNSServer is started with "*" for domain name, it will reply with
|
||||
// provided IP to all DNS request
|
||||
@ -269,16 +420,30 @@ setup()
|
||||
webServer.on("/fwlink", handleRoot); // Microsoft captive portal.
|
||||
|
||||
webServer.on("/", handleRoot);
|
||||
webServer.on("/auth", handleAuth);
|
||||
webServer.on("/"+FORCERESTARENDPOINT,[]()
|
||||
{
|
||||
reset_game();
|
||||
webServer.send(200, "text/plain",
|
||||
"A caixa foi reiniciada com sucesso!");});
|
||||
webServer.on("/game", handleGame);
|
||||
webServer.on("/style.css", return_css);
|
||||
|
||||
webServer.on("/switch_state", switch_led);
|
||||
webServer.on("/game/switch_state", switch_led);
|
||||
|
||||
webServer.on("/won", won_game);
|
||||
webServer.on("/game/won", won_game);
|
||||
|
||||
webServer.onNotFound(handleNotFound);
|
||||
//webServer.onNotFound(handleNotFound);
|
||||
webServer.onNotFound(handleRoot);
|
||||
|
||||
// Start WebServer
|
||||
webServer.begin();
|
||||
Serial.println("HTTP server started");
|
||||
|
||||
/*** Start game ***/
|
||||
generate_password();
|
||||
// print password
|
||||
print_binary_string(password);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user