Compare commits

...

7 Commits

Author SHA1 Message Date
radex 78ebf2c1a4
customize: core length 2024-02-28 15:44:30 +01:00
radex 9014650fed
add generic number_input 2024-02-28 15:07:13 +01:00
radex 3a5af46135
customize: wire diamater 2024-02-28 14:06:06 +01:00
radex fe37eea8de
keyboard: fix key to digit 2024-02-28 14:05:22 +01:00
radex fe220120cc
basic main menu 2024-02-22 16:27:04 +01:00
radex 43c12c65a5
custom characters contd 2024-02-22 15:59:27 +01:00
radex a88212a40d
screen: custom characters 2024-02-22 00:25:06 +01:00
16 changed files with 514 additions and 17 deletions

155
firmware/src/characters.cpp Normal file
View File

@ -0,0 +1,155 @@
#include "characters.h"
uint8_t invertedA[8] = {
0b11111,
0b10001,
0b10101,
0b10001,
0b10101,
0b10101,
0b11111,
0b00000,
};
uint8_t invertedB[8] = {
0b11111,
0b10011,
0b10101,
0b10011,
0b10101,
0b10011,
0b11111,
0b00000,
};
uint8_t invertedC[8] = {
0b11111,
0b11001,
0b10111,
0b10111,
0b10111,
0b11001,
0b11111,
0b00000,
};
uint8_t invertedD[8] = {
0b11111,
0b10011,
0b10101,
0b10101,
0b10101,
0b10011,
0b11111,
0b00000,
};
uint8_t encoder[8] = {
0b01110,
0b10001,
0b00011,
0b11000,
0b10001,
0b01110,
0b00000,
0b00000,
};
uint8_t encoderSwitch[8] = {
0b00000,
0b01110,
0b10001,
0b10101,
0b10001,
0b01110,
0b00000,
0b00000,
};
uint8_t progressLeftMask[8] = {
0b10000,
0b00000,
0b00000,
0b00000,
0b00000,
0b00000,
0b10000,
0b00000,
};
uint8_t progressRightMask[8] = {
0b00001,
0b00000,
0b00000,
0b00000,
0b00000,
0b00000,
0b00001,
0b00000,
};
uint8_t progress0[8] = {
0b11111,
0b00000,
0b00000,
0b00000,
0b00000,
0b00000,
0b11111,
0b00000,
};
uint8_t progress1[8] = {
0b11111,
0b10000,
0b10000,
0b10000,
0b10000,
0b10000,
0b11111,
0b00000,
};
uint8_t progress2[8] = {
0b11111,
0b11000,
0b11000,
0b11000,
0b11000,
0b11000,
0b11111,
0b00000,
};
uint8_t progress3[8] = {
0b11111,
0b11100,
0b11100,
0b11100,
0b11100,
0b11100,
0b11111,
0b00000,
};
uint8_t progress4[8] = {
0b11111,
0b11110,
0b11110,
0b11110,
0b11110,
0b11110,
0b11111,
0b00000,
};
uint8_t progress5[8] = {
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b00000,
};

25
firmware/src/characters.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include <Arduino.h>
#define CHAR_INVERTED_A 0
#define CHAR_INVERTED_B 1
#define CHAR_INVERTED_C 2
#define CHAR_INVERTED_D 3
#define CHAR_ENCODER 4
#define CHAR_ENCODER_SWITCH 5
#define CHAR_SELECTION 0b01111110
extern uint8_t invertedA[8];
extern uint8_t invertedB[8];
extern uint8_t invertedC[8];
extern uint8_t invertedD[8];
extern uint8_t encoder[8];
extern uint8_t encoderSwitch[8];
extern uint8_t progressLeftMask[8];
extern uint8_t progressRightMask[8];
extern uint8_t progress0[8];
extern uint8_t progress1[8];
extern uint8_t progress2[8];
extern uint8_t progress3[8];
extern uint8_t progress4[8];
extern uint8_t progress5[8];

View File

@ -0,0 +1,55 @@
#include "screen.h"
#include "number_input.h"
#include "buzzer.h"
void customize_setup();
float wireDiameter = -1;
float coreLength = -1;
void customize() {
setup:
wireDiameter = -1;
coreLength = -1;
wireDiameterStep:
lcd.clear();
lcd.print("Wire diameter:");
lcd.setCursor(14, 1);
lcd.print("mm");
float inputWireDiameter = number_input(wireDiameter, 0.1);
tick();
if (inputWireDiameter == NUMBER_INPUT_BACK) {
return;
} else {
wireDiameter = inputWireDiameter;
Serial.print("Selected wire diameter: ");
Serial.println(wireDiameter);
}
coreLengthStep:
lcd.clear();
lcd.print("Core length:");
lcd.setCursor(14, 1);
lcd.print("mm");
float inputCoreLength = number_input(coreLength, 0.1);
tick();
if (inputCoreLength == NUMBER_INPUT_BACK) {
goto wireDiameterStep;
} else {
coreLength = inputCoreLength;
Serial.print("Selected core length: ");
Serial.println(coreLength);
}
lcd.clear();
lcd.print("Customization done");
delay(1000);
}
void customize_setup() {
}

3
firmware/src/customize.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
void customize();

View File

@ -9,6 +9,7 @@ I2CScanner scanner;
#include "keyboard.h"
#include "stepper.h"
#include "input.h"
#include "characters.h"
void setupDebug() {
pinMode(LED_BUILTIN, OUTPUT);
@ -93,6 +94,14 @@ void handleDebugFunctions(char key) {
setTimerEnabled(!isTimerEnabled());
} else if (key == 'q') {
quickAccelerate();
} else if (key == '\\') {
lcd.clear();
lcd.write(CHAR_INVERTED_A);
lcd.write(CHAR_INVERTED_B);
lcd.write(CHAR_INVERTED_C);
lcd.write(CHAR_INVERTED_D);
lcd.write(CHAR_ENCODER);
lcd.write(CHAR_ENCODER_SWITCH);
}
}
@ -105,7 +114,7 @@ void debugHandleInput(Input input) {
Serial.print(allKeys[input.key]);
auto digit = getPressedDigit(input.key);
if (digit != KEY_NONE) {
if (digit != -1) {
Serial.print(", digit: ");
Serial.print(digit);
} else {

View File

@ -10,3 +10,9 @@ Input getInput() {
return {debugKey, key, switchEvent, encoderEvent, hasInput};
}
Input handleInput() {
auto input = getInput();
debugHandleInput(input);
return input;
}

View File

@ -13,3 +13,4 @@ struct Input {
};
Input getInput();
Input handleInput();

View File

@ -21,12 +21,12 @@ row/col 0 1 2 3
const char *allKeys = " 123A456B789C*0#D";
const uint8_t digits[17] =
{ KEY_NONE,
1, 2, 3, KEY_NONE,
4, 5, 6, KEY_NONE,
7, 8, 9, KEY_NONE,
KEY_NONE, 0, KEY_NONE, KEY_NONE};
const int8_t digits[17] =
{ -1,
1, 2, 3, -1,
4, 5, 6, -1,
7, 8, 9, -1,
-1, 0, -1, -1};
bool setupKeyboard() {
if (!kbd.begin()) {
@ -126,7 +126,7 @@ Key getPressedKey() {
return (rowPressed * 4) + colPressed + 1;
}
uint8_t getPressedDigit(Key key) {
int8_t getPressedDigit(Key key) {
return digits[key];
}

View File

@ -29,8 +29,8 @@ bool setupKeyboard();
Key handleKeyboard();
/**
* Returns pressed digit or KEY_NONE if the key is not a digit
* Returns pressed digit or -1 if the key is not a digit
*/
uint8_t getPressedDigit(Key key);
int8_t getPressedDigit(Key key);
Key handleDebugKeyboard(char key);

View File

@ -11,6 +11,7 @@
#include "memes.h"
#include "input.h"
#include "spindle.h"
#include "menu.h"
void setup() {
setupDebug();
@ -21,6 +22,7 @@ void setup() {
Wire.begin();
Wire.setClock(800000);
debugScanI2C();
if (!setupScreen()) {
fatal();
@ -33,15 +35,9 @@ void setup() {
}
splashScreen();
menu();
}
void loop() {
debugScanI2C();
auto input = getInput();
if (input.hasInput) {
tick();
}
debugHandleInput(input);
}

View File

@ -25,4 +25,5 @@ void splashScreen() {
delay(300);
lcd.setCursor(0, 1);
lcd.print("by");
delay(1000);
}

71
firmware/src/menu.cpp Normal file
View File

@ -0,0 +1,71 @@
#include "input.h"
#include "buzzer.h"
#include "screen.h"
#include "characters.h"
#include "customize.h"
uint8_t menuPos = 0;
#define MENU_ITEMS 2
void menu_setup();
void menu_update();
void help();
void menu() {
menu_setup();
while (true) {
auto input = handleInput();
if (input.encoderEvent) {
tick();
menuPos = (menuPos + input.encoderEvent) % MENU_ITEMS;
if (menuPos == 255) {
menuPos = MENU_ITEMS - 1;
}
menu_update();
} else if (input.switchEvent == SWITCH_RELEASED) {
switch (menuPos) {
case 0:
customize();
break;
case 1:
help();
break;
}
menu_setup();
} else if (input.hasInput && input.switchEvent != SWITCH_PRESSED) {
beep();
}
}
}
void menu_setup() {
menuPos = 0;
lcd.clear();
lcd.print(" Wind coils");
lcd.setCursor(0, 1);
lcd.print(" Help");
menu_update();
}
void menu_update() {
lcd.setCursor(0, 0);
lcd.write(menuPos == 0 ? CHAR_SELECTION : ' ');
lcd.setCursor(0, 1);
lcd.write(menuPos == 1 ? CHAR_SELECTION : ' ');
}
void help() {
lcd.clear();
lcd.print("Use the source");
lcd.setCursor(0, 1);
lcd.print("code, Luke ;^)");
beep();
while (true) {
auto input = handleInput();
if (input.hasInput && input.switchEvent != SWITCH_PRESSED) {
tick();
break;
}
}
}

3
firmware/src/menu.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
void menu();

View File

@ -0,0 +1,140 @@
#include "input.h"
#include "buzzer.h"
#include "screen.h"
#include "characters.h"
#include "number_input.h"
String numberInput = "";
int8_t dotPosition = -1;
#define MAX_LENGTH 8
void number_input_update();
float number_input(float defaultValue, float encoderStep) {
// setup
if (defaultValue < 0) {
numberInput = "";
dotPosition = -1;
} else {
// see how many decimal places the default value has (max 3)
unsigned char decimalPlaces = 3;
numberInput = String(defaultValue, decimalPlaces);
if (numberInput.endsWith(".000")) {
decimalPlaces = 0;
} else if (numberInput.endsWith("00")) {
decimalPlaces = 1;
} else if (numberInput.endsWith("0")) {
decimalPlaces = 2;
}
// stringify again
numberInput = String(defaultValue, decimalPlaces);
dotPosition = numberInput.indexOf('.');
if (numberInput.length() > MAX_LENGTH) {
beep();
numberInput = numberInput.substring(0, MAX_LENGTH);
}
}
// set up screen
lcd.cursor();
number_input_update();
// loop
while (true) {
auto input = handleInput();
auto len = numberInput.length();
bool isAtLength = len >= MAX_LENGTH;
if (input.key == KEY_C || input.switchEvent == SWITCH_RELEASED) {
if (numberInput.length() > 0) {
lcd.noCursor();
return numberInput.toFloat();
} else {
beep();
}
} else if (input.key) {
auto digit = getPressedDigit(input.key);
if (digit != -1) {
// append digit (if it fits)
if (isAtLength) {
beep();
} else {
numberInput += digit;
tick();
}
} else if (input.key == KEY_ASTERISK) {
// append decimal point (if possible)
if (isAtLength) {
beep();
} else if (dotPosition == -1 && len >= 1) {
dotPosition = numberInput.length();
numberInput += ".";
tick();
} else {
beep();
}
} else if (input.key == KEY_HASH) {
// backspace
if (len) {
if (dotPosition == len - 1) {
dotPosition = -1;
}
numberInput = numberInput.substring(0, len - 1);
tick();
} else {
beep();
}
} else if (input.key == KEY_B) {
lcd.noCursor();
return NUMBER_INPUT_BACK;
} else {
beep();
}
number_input_update();
} else if (input.encoderEvent) {
// normalize input
if (numberInput.length() == 0) {
numberInput = "0";
}
// remember decimal places
len = numberInput.length();
auto previousDecimalPlaces = dotPosition == -1 ? 0 : len - dotPosition - 1;
// calculate new value
auto wireDia = numberInput.toFloat();
wireDia += input.encoderEvent * encoderStep;
// clamp to 0
if (wireDia < 0) {
wireDia = 0;
beep();
} else {
tick();
}
// stringify
numberInput = String(wireDia, max(previousDecimalPlaces, 1));
dotPosition = numberInput.indexOf('.');
number_input_update();
} else if (input.switchEvent == SWITCH_RELEASED) {
} else if (input.hasInput && input.switchEvent != SWITCH_PRESSED) {
beep();
}
}
}
void number_input_update() {
lcd.setCursor(0, 1);
lcd.print(numberInput);
// Delete following character (if backspace was pressed), then move cursor back to position
lcd.write(' ');
lcd.setCursor(numberInput.length(), 1);
}

View File

@ -0,0 +1,21 @@
#pragma once
#define NUMBER_INPUT_BACK -1
/**
* Uses second row of the screen, keyboard, and encoder to get a number from the user.
*
* Number cannot be longer than 8 characters, or less than 0.
*
* If defaultValue is -1, it will default to empty string.
* defaultValue will be truncated to at most 3 decimal places.
*
* It will return the number when it's confirmed by encoder press or [C]ontinue.
* It will return NUMBER_INPUT_BACK if [B]ack is pressed.
*
* LCD is set to .noCursor() before returning.
*/
float number_input(
float defaultValue,
float encoderStep
);

View File

@ -1,6 +1,7 @@
#include "constants.h"
#include <LCD_I2C.h>
#include <Wire.h>
#include "characters.h"
LCD_I2C lcd(LCD_I2C_ADDR, LCD_COLS, LCD_ROWS);
@ -15,5 +16,15 @@ bool setupScreen() {
lcd.backlight();
lcd.clear();
// add custom characters to CGROM
// can only add 8 custom characters ,_,
lcd.createChar(CHAR_INVERTED_A, invertedA);
lcd.createChar(CHAR_INVERTED_B, invertedB);
lcd.createChar(CHAR_INVERTED_C, invertedC);
lcd.createChar(CHAR_INVERTED_D, invertedD);
lcd.createChar(CHAR_ENCODER, encoder);
lcd.createChar(CHAR_ENCODER_SWITCH, encoderSwitch);
return true;
}