Math and morse modules done
This commit is contained in:
commit
106a7dfe2d
|
@ -0,0 +1,2 @@
|
||||||
|
/*/build/
|
||||||
|
/*/.vscode/
|
|
@ -0,0 +1,14 @@
|
||||||
|
#include <M5StickCPlus.h>
|
||||||
|
void setup() {
|
||||||
|
M5.begin();
|
||||||
|
M5.Lcd.fillScreen(WHITE);
|
||||||
|
|
||||||
|
pinMode(26, OUTPUT_OPEN_DRAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
digitalWrite(26, HIGH);
|
||||||
|
delay(25);
|
||||||
|
digitalWrite(26, LOW);
|
||||||
|
delay(25);
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
#include <M5StickCPlus.h>
|
||||||
|
|
||||||
|
#define buttonPin 25
|
||||||
|
#define inputPauseRegisterMills 1500
|
||||||
|
|
||||||
|
typedef void (*OnFinishInputMode)(int);
|
||||||
|
OnFinishInputMode onFinishInputMode = nullptr;
|
||||||
|
|
||||||
|
int pressedTimes = 0;
|
||||||
|
bool isInputMode = false;
|
||||||
|
|
||||||
|
long lastInputTime = 0;
|
||||||
|
void onPressed(){
|
||||||
|
if (!isInputMode)
|
||||||
|
{
|
||||||
|
isInputMode = true;
|
||||||
|
}
|
||||||
|
lastInputTime = millis();
|
||||||
|
|
||||||
|
pressedTimes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// void m_onFinishInputMode(){
|
||||||
|
// M5.Lcd.fillScreen(WHITE);
|
||||||
|
// M5.Lcd.setTextPadding(10);
|
||||||
|
// M5.Lcd.setCursor(10, 10);
|
||||||
|
// M5.Lcd.setTextSize(6);
|
||||||
|
// M5.Lcd.print(pressedTimes);
|
||||||
|
|
||||||
|
// Serial.println("Registed: " + pressedTimes);
|
||||||
|
|
||||||
|
// // Reset count
|
||||||
|
// pressedTimes = 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
bool buttonDowned = false;
|
||||||
|
void updateInput()
|
||||||
|
{
|
||||||
|
// Detect button down
|
||||||
|
if (!buttonDowned && digitalRead(buttonPin) == LOW)
|
||||||
|
{
|
||||||
|
buttonDowned = true;
|
||||||
|
|
||||||
|
onPressed();
|
||||||
|
}
|
||||||
|
else if (buttonDowned && digitalRead(buttonPin) == HIGH)
|
||||||
|
{
|
||||||
|
buttonDowned = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect if no input for 3 seconds
|
||||||
|
if (isInputMode && millis() - lastInputTime > inputPauseRegisterMills)
|
||||||
|
{
|
||||||
|
isInputMode = false;
|
||||||
|
if (onFinishInputMode != nullptr)
|
||||||
|
onFinishInputMode(pressedTimes);
|
||||||
|
|
||||||
|
pressedTimes = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initInputSystem(OnFinishInputMode callback)
|
||||||
|
{
|
||||||
|
onFinishInputMode = callback;
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
#include <M5StickCPlus.h>
|
||||||
|
|
||||||
|
// -1 if error
|
||||||
|
int a = 0;
|
||||||
|
int b = 0;
|
||||||
|
int targetResult = 0;
|
||||||
|
|
||||||
|
enum class Operator{
|
||||||
|
plus,
|
||||||
|
minus,
|
||||||
|
mult
|
||||||
|
};
|
||||||
|
|
||||||
|
void initRandomSeed(){
|
||||||
|
M5.IMU.Init();
|
||||||
|
float accX, accY, accZ;
|
||||||
|
delay(250); // Wait for imu init
|
||||||
|
M5.IMU.getAccelData(&accX, &accY, &accZ);
|
||||||
|
float accelSum = accX + accY + accZ;
|
||||||
|
|
||||||
|
unsigned long seed = accelSum * 1000000;
|
||||||
|
randomSeed(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
String generateQuestion(){
|
||||||
|
Operator oper = static_cast<Operator>(random(0, 3));
|
||||||
|
switch (oper)
|
||||||
|
{
|
||||||
|
case Operator::plus:
|
||||||
|
a = random(0, 15);
|
||||||
|
b = random(1, 15);
|
||||||
|
|
||||||
|
targetResult = a + b;
|
||||||
|
return String(a) + "+" + String(b) + " = ?";
|
||||||
|
|
||||||
|
case Operator::minus:
|
||||||
|
do
|
||||||
|
{
|
||||||
|
a = random(15, 30);
|
||||||
|
b = random(0, 15);
|
||||||
|
|
||||||
|
targetResult = a - b;
|
||||||
|
} while (targetResult <= 0);
|
||||||
|
return String(a) + "-" + String(b) + "= ?";
|
||||||
|
|
||||||
|
case Operator::mult:
|
||||||
|
a = random(0, 10);
|
||||||
|
b = random(1, 10);
|
||||||
|
|
||||||
|
targetResult = a * b;
|
||||||
|
return String(a) + "*" + String(b) + "= ?";
|
||||||
|
|
||||||
|
default:
|
||||||
|
Serial.println("Failed to create math question");
|
||||||
|
return "Error";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
#include <M5StickCPlus.h>
|
||||||
|
#include "InputSystem.h"
|
||||||
|
#include "MathSystem.h"
|
||||||
|
|
||||||
|
#define extenderPin 26
|
||||||
|
#define buttonPin 25
|
||||||
|
|
||||||
|
#define UIRefreshDelay 250
|
||||||
|
|
||||||
|
String mathExpression = "";
|
||||||
|
bool hasWon = false;
|
||||||
|
|
||||||
|
void onInputDone(int inputNum){
|
||||||
|
Serial.println("Reveiced: " + String(inputNum));
|
||||||
|
Serial.println("Target: " + String(targetResult));
|
||||||
|
|
||||||
|
if (inputNum == targetResult){
|
||||||
|
hasWon = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasWon){
|
||||||
|
M5.Lcd.fillScreen(RED);
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
M5.begin();
|
||||||
|
M5.Lcd.setRotation(1);
|
||||||
|
|
||||||
|
initRandomSeed();
|
||||||
|
|
||||||
|
digitalWrite(extenderPin, HIGH); // Push out
|
||||||
|
|
||||||
|
pinMode(extenderPin, OUTPUT_OPEN_DRAIN);
|
||||||
|
pinMode(buttonPin, INPUT_PULLUP);
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
mathExpression = generateQuestion();
|
||||||
|
|
||||||
|
initInputSystem(*onInputDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawUI(){
|
||||||
|
if (!hasWon)
|
||||||
|
{
|
||||||
|
M5.Lcd.fillScreen(BLACK);
|
||||||
|
|
||||||
|
if (!isInputMode)
|
||||||
|
{
|
||||||
|
// Draw expression
|
||||||
|
M5.Lcd.setCursor(10, 50);
|
||||||
|
M5.Lcd.setTextSize(4);
|
||||||
|
M5.Lcd.print(mathExpression);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Draw pressed times
|
||||||
|
M5.Lcd.setCursor(80, 40);
|
||||||
|
M5.Lcd.setTextSize(7);
|
||||||
|
M5.Lcd.print(pressedTimes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
M5.Lcd.fillScreen(GREEN);
|
||||||
|
digitalWrite(extenderPin, LOW);
|
||||||
|
|
||||||
|
// Wait for reset click
|
||||||
|
while (digitalRead(buttonPin) == HIGH){
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
while (digitalRead(buttonPin) == LOW)
|
||||||
|
{
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset
|
||||||
|
digitalWrite(extenderPin, HIGH);
|
||||||
|
mathExpression = generateQuestion();
|
||||||
|
hasWon = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
updateInput();
|
||||||
|
|
||||||
|
if (isInputMode || millis() % UIRefreshDelay < 100)
|
||||||
|
drawUI();
|
||||||
|
|
||||||
|
delay(25);
|
||||||
|
}
|
|
@ -0,0 +1,197 @@
|
||||||
|
#include <M5StickCPlus.h>
|
||||||
|
#include "MorsePart.h"
|
||||||
|
|
||||||
|
#define refreshDelay 1000
|
||||||
|
|
||||||
|
#define BTN_A 37
|
||||||
|
#define BTN_B 39
|
||||||
|
|
||||||
|
#define extenderPin 26
|
||||||
|
|
||||||
|
int currentlySelected = 1000;
|
||||||
|
|
||||||
|
const int numCodes = 11;
|
||||||
|
const String codes[] = {
|
||||||
|
"bond", "swap", "call", "repo", "yield", "index", "asset", "bear", "bull", "gain", "loss"};
|
||||||
|
|
||||||
|
#define selectedDisplayLength 0 // Used for debug but not used for production
|
||||||
|
bool isSelectionMode = false;
|
||||||
|
long onSelectedTime = 0;
|
||||||
|
|
||||||
|
int correctIndex;
|
||||||
|
|
||||||
|
bool hasWon = false;
|
||||||
|
|
||||||
|
void initRandomSeed()
|
||||||
|
{
|
||||||
|
M5.IMU.Init();
|
||||||
|
float accX, accY, accZ;
|
||||||
|
delay(250); // Wait for imu init
|
||||||
|
M5.IMU.getAccelData(&accX, &accY, &accZ);
|
||||||
|
float accelSum = accX + accY + accZ;
|
||||||
|
|
||||||
|
unsigned long seed = accelSum * 1000000;
|
||||||
|
randomSeed(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
M5.begin();
|
||||||
|
M5.Lcd.setRotation(1);
|
||||||
|
M5.Lcd.fillScreen(BLACK);
|
||||||
|
|
||||||
|
pinMode(BTN_A, INPUT_PULLDOWN);
|
||||||
|
pinMode(BTN_B, INPUT_PULLDOWN);
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
updateUI();
|
||||||
|
|
||||||
|
initRandomSeed();
|
||||||
|
//correctIndex = 1;
|
||||||
|
correctIndex = random(0, 12);
|
||||||
|
|
||||||
|
morseInit(correctIndex, 0, 0, 300, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateUI()
|
||||||
|
{
|
||||||
|
Serial.println("Next correct: " + codes[correctIndex]);
|
||||||
|
|
||||||
|
// Clear screen
|
||||||
|
M5.Lcd.fillRect(0, 100, 300, 100, BLACK);
|
||||||
|
|
||||||
|
if (hasWon)
|
||||||
|
{
|
||||||
|
M5.Lcd.fillScreen(GREEN);
|
||||||
|
digitalWrite(extenderPin, LOW);
|
||||||
|
|
||||||
|
delay(3000);
|
||||||
|
|
||||||
|
// Wait for reset click
|
||||||
|
while (digitalRead(BTN_A) == HIGH || digitalRead(BTN_B) == HIGH)
|
||||||
|
{
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
while (digitalRead(BTN_A) == HIGH || digitalRead(BTN_B) == HIGH)
|
||||||
|
{
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
digitalWrite(extenderPin, HIGH);
|
||||||
|
hasWon = false;
|
||||||
|
M5.Lcd.fillScreen(BLUE);
|
||||||
|
correctIndex = random(0, 12);
|
||||||
|
delay(1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSelectionMode)
|
||||||
|
{
|
||||||
|
// Draw divider
|
||||||
|
M5.Lcd.drawLine(0, 100, 300, 100, WHITE);
|
||||||
|
|
||||||
|
// Draw left text
|
||||||
|
M5.Lcd.setTextSize(2);
|
||||||
|
M5.Lcd.setCursor(20, 110);
|
||||||
|
M5.Lcd.setTextColor(WHITE);
|
||||||
|
M5.Lcd.print(codes[(currentlySelected - 1) % numCodes]);
|
||||||
|
// Draw selected text
|
||||||
|
M5.Lcd.fillRect(90, 110 - 5, 14 * 5, 25, WHITE);
|
||||||
|
M5.Lcd.setTextSize(2);
|
||||||
|
M5.Lcd.setCursor(95, 110);
|
||||||
|
M5.Lcd.setTextColor(BLACK);
|
||||||
|
M5.Lcd.print(codes[(currentlySelected) % numCodes]);
|
||||||
|
// Draw right text
|
||||||
|
M5.Lcd.setTextSize(2);
|
||||||
|
M5.Lcd.setCursor(175, 110);
|
||||||
|
M5.Lcd.setTextColor(WHITE);
|
||||||
|
M5.Lcd.print(codes[(currentlySelected + 1) % numCodes]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Draw selected text
|
||||||
|
M5.Lcd.setTextSize(4);
|
||||||
|
M5.Lcd.setCursor(10, 20);
|
||||||
|
M5.Lcd.setTextColor(WHITE);
|
||||||
|
M5.Lcd.print(codes[(currentlySelected) % numCodes]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onBothPressed()
|
||||||
|
{
|
||||||
|
isSelectionMode = true;
|
||||||
|
Serial.println("Selected: " + codes[(currentlySelected) % numCodes]);
|
||||||
|
updateUI();
|
||||||
|
|
||||||
|
if (correctIndex == (currentlySelected) % numCodes)
|
||||||
|
hasWon = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
M5.Lcd.fillScreen(RED);
|
||||||
|
|
||||||
|
delay(3000);
|
||||||
|
|
||||||
|
morseDisplayIndex = 0; // Reset morse
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectedTime = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isButtonAPressed, isButtonBPressed = false;
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
morseUpdate();
|
||||||
|
|
||||||
|
if (millis() % refreshDelay < 100)
|
||||||
|
updateUI();
|
||||||
|
|
||||||
|
if (!isButtonAPressed && digitalRead(BTN_A) == LOW)
|
||||||
|
{
|
||||||
|
isButtonAPressed = true;
|
||||||
|
//Serial.println("A pressed");
|
||||||
|
|
||||||
|
if (isButtonBPressed)
|
||||||
|
{
|
||||||
|
onBothPressed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isButtonAPressed && digitalRead(BTN_A) == HIGH)
|
||||||
|
{
|
||||||
|
isButtonAPressed = false;
|
||||||
|
//Serial.println("A released");
|
||||||
|
if (!isSelectionMode)
|
||||||
|
{
|
||||||
|
currentlySelected++;
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isButtonBPressed && digitalRead(BTN_B) == LOW)
|
||||||
|
{
|
||||||
|
isButtonBPressed = true;
|
||||||
|
//Serial.println("B pressed");
|
||||||
|
|
||||||
|
if (isButtonAPressed)
|
||||||
|
{
|
||||||
|
onBothPressed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isButtonBPressed && digitalRead(BTN_B) == HIGH)
|
||||||
|
{
|
||||||
|
isButtonBPressed = false;
|
||||||
|
//Serial.println("B released");
|
||||||
|
if (!isSelectionMode)
|
||||||
|
{
|
||||||
|
currentlySelected--;
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSelectionMode && onSelectedTime + selectedDisplayLength < millis())
|
||||||
|
{
|
||||||
|
isSelectionMode = false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
#include <M5StickCPlus.h>
|
||||||
|
|
||||||
|
#define nextItemDelayTime 500
|
||||||
|
|
||||||
|
#define dotDisplayTime 500 + nextItemDelayTime
|
||||||
|
#define dashDisplayTime 1500 + nextItemDelayTime
|
||||||
|
#define nextLetterDelayTime 1000
|
||||||
|
#define restartDelayTime 5000
|
||||||
|
|
||||||
|
const String morseCodes[11] = {
|
||||||
|
"-.../---/-./-..;", // "bond"
|
||||||
|
".../.--/.-/.--.;", // "swap"
|
||||||
|
"-.-./.-/.-../.-..;", // "call"
|
||||||
|
".-././.--./---;", // "repo"
|
||||||
|
"-.--/./../.-../-..;", // "yield"
|
||||||
|
"../-./-.././-..-;", // "index"
|
||||||
|
".-/.../..././-;", // "asset"
|
||||||
|
"-..././.-/.-.;", // "bear"
|
||||||
|
"-.../..-/.-../.-..;", // "bull"
|
||||||
|
"--./.-/../-.;", // "gain"
|
||||||
|
".-../---/.../...;" // "loss"
|
||||||
|
};
|
||||||
|
|
||||||
|
int x, y, w, h;
|
||||||
|
|
||||||
|
int morseDisplayIndex = -1; // Which char iscurrently going to be displayed
|
||||||
|
int morseCodeLength;
|
||||||
|
int morseCorrectIndex;
|
||||||
|
|
||||||
|
void morseInit(int CorrectIndex, int X, int Y, int W, int H)
|
||||||
|
{
|
||||||
|
x = X;
|
||||||
|
y = Y;
|
||||||
|
w = W;
|
||||||
|
h = H;
|
||||||
|
morseCorrectIndex = CorrectIndex;
|
||||||
|
morseCodeLength = strlen(morseCodes[CorrectIndex].c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isLit = false;
|
||||||
|
long getDisplayTime(char morseChar)
|
||||||
|
{
|
||||||
|
switch (morseChar)
|
||||||
|
{
|
||||||
|
case '.':
|
||||||
|
isLit = true;
|
||||||
|
Serial.println("dot");
|
||||||
|
return dotDisplayTime;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
isLit = true;
|
||||||
|
Serial.println("dash");
|
||||||
|
return dashDisplayTime;
|
||||||
|
|
||||||
|
case '/':
|
||||||
|
isLit = false;
|
||||||
|
Serial.println("space");
|
||||||
|
return nextLetterDelayTime;
|
||||||
|
|
||||||
|
case ';':
|
||||||
|
isLit = false;
|
||||||
|
Serial.println("stop");
|
||||||
|
return restartDelayTime;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long actionStartTime = 0;
|
||||||
|
long actionDurationTime = 0;
|
||||||
|
void morseUpdate()
|
||||||
|
{
|
||||||
|
long currentTime = millis();
|
||||||
|
if (actionStartTime + actionDurationTime < currentTime)
|
||||||
|
{
|
||||||
|
morseDisplayIndex++;
|
||||||
|
actionStartTime = currentTime;
|
||||||
|
|
||||||
|
// get next display time
|
||||||
|
char nextChar = morseCodes[morseCorrectIndex][morseDisplayIndex % morseCodeLength];
|
||||||
|
actionDurationTime = getDisplayTime(nextChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLit && actionStartTime + actionDurationTime - nextItemDelayTime < currentTime)
|
||||||
|
{
|
||||||
|
isLit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLit)
|
||||||
|
M5.Lcd.fillRect(x, y, w, h, WHITE);
|
||||||
|
else
|
||||||
|
M5.Lcd.fillRect(x, y, w, h, BLACK);
|
||||||
|
}
|
Loading…
Reference in New Issue