Math and morse modules done

This commit is contained in:
BOT Alex 2024-05-02 14:02:09 +02:00
commit 106a7dfe2d
7 changed files with 520 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/*/build/
/*/.vscode/

14
Base/Base/Base.ino Normal file
View File

@ -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);
}

65
ModuleMath/InputSystem.h Normal file
View File

@ -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;
}

57
ModuleMath/MathSystem.h Normal file
View File

@ -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";
}
}

91
ModuleMath/ModuleMath.ino Normal file
View File

@ -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);
}

197
ModuleMorse/ModuleMorse.ino Normal file
View File

@ -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;
}
}

94
ModuleMorse/MorsePart.h Normal file
View File

@ -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);
}