MacroBoard-ArduinoCode/Maybe/Maybe.ino

587 lines
12 KiB
Arduino
Raw Normal View History

2022-09-15 20:34:54 +00:00
/*
Macro Board
Made by Bozarre
*/
/*
* saving presets in eeprom
*/
#include <EEPROM.h>
2022-09-16 21:17:37 +00:00
struct MemSlot
{
2022-09-18 12:38:00 +00:00
String displayName;
int address;
2022-09-16 21:17:37 +00:00
byte value;
};
2022-09-18 12:38:00 +00:00
MemSlot memory[] = //128 bytes for the Teensy LC
2022-09-18 14:09:53 +00:00
{
2022-09-21 22:32:30 +00:00
{"alt", 1, 0}, //preset
2022-09-21 12:12:39 +00:00
{"bt1", 2, 0}, //button mode (0 = default, 1 = toggle)
{"bt2", 3, 0},
{"bt3", 4, 0},
{"bt4", 5, 0},
{"bt5", 6, 0},
{"bt6", 7, 0},
{"bt7", 8, 0},
{"bt8", 9, 0},
{"bt9", 10, 0},
{"bt10", 11, 0},
{"bt11", 12, 0},
{"bt12", 13, 0},
2022-09-21 17:18:16 +00:00
{"effc", 14, 1},
2022-09-21 22:32:30 +00:00
{"afps", 15, 24},
{"clea", 0, 0}, // != 0 -> reset eeprom
2022-09-18 12:38:00 +00:00
};
/*
* Menu
*/
bool isInMenu = false;
struct MenuItem
{
String path;
bool isValue;
String displayName;
};
MenuItem menuEntries[] =
{
2022-09-21 22:32:30 +00:00
{"", true, "alt"},
{"", false, "btn"},
2022-09-21 17:18:16 +00:00
{"", true, "effc"},
2022-09-21 22:32:30 +00:00
{"", true, "afps"},
{"", true, "clea"},
{"/btn", true, "bt1"},
{"/btn", true, "bt2"},
{"/btn", true, "bt3"},
{"/btn", true, "bt4"},
{"/btn", true, "bt5"},
{"/btn", true, "bt6"},
{"/btn", true, "bt7"},
{"/btn", true, "bt8"},
{"/btn", true, "bt9"},
{"/btn", true, "bt10"},
{"/btn", true, "bt11"},
{"/btn", true, "bt12"},
2022-09-18 12:38:00 +00:00
};
2022-09-16 21:17:37 +00:00
2022-09-18 12:38:00 +00:00
String menuCurrentPath = "";
unsigned int menuSelectionIndex = 0;
unsigned int menuCurrentPathItems = 0;
MenuItem menuCurrentItem;
bool menuIsSettingValue = false;
2022-09-16 21:17:37 +00:00
2022-09-15 20:34:54 +00:00
/*
* 7 Segment 4 digits display
*/
#include "SevSeg.h"
2022-09-16 21:17:37 +00:00
2022-09-15 20:34:54 +00:00
SevSeg sevseg;
/*
* key button matrix
*/
#include <Keypad.h>
const byte rows = 4; //four rows
const byte cols = 3; //three columns
//Hardware inputs ordered from the bottom left = 1 to the top right = 12 on the switch matrix,
2022-09-15 20:34:54 +00:00
char keys[rows][cols] = { // assiging arbitraty uid to each button
2022-09-18 12:38:00 +00:00
{9,5,1},
{10,6,2},
{11,7,3},
{12,8,4}
2022-09-15 20:34:54 +00:00
};
byte rowPins[rows] = {1, 2, 3, 0}; //connect to the row pinouts of the keypad
byte colPins[cols] = {21, 22, 23}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, rows, cols );
2022-09-21 12:12:39 +00:00
bool buttonsVirtualState[] =
{
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
};
2022-09-15 20:34:54 +00:00
/*
* Rotary Encoder
*/
#include <SimpleRotary.h>
SimpleRotary rotaryEncoder(19, 20, 4);
byte rotaryEncoderState = 0;
// Rotary push button
const int BUTTON_Rotary = 4;
2022-09-16 21:17:37 +00:00
2022-09-18 12:38:00 +00:00
/*
* mode presets and action
*/
#include "modeAction.h"
2022-09-16 21:17:37 +00:00
/*
* custom display animations
*/
#include "animations.h"
2022-09-16 21:17:37 +00:00
int animationFrame = 0;
bool animationPlaying = false;
unsigned int animationLastFrameMillis = 0;
unsigned int animationFrameDelayMillis = 64;
bool animationLooping = false;
2022-09-21 17:18:16 +00:00
bool animationEnabled = true;
2022-09-16 21:17:37 +00:00
2022-09-18 12:38:00 +00:00
/*
* time cooldown managment
*/
unsigned int lastInputMillis = 0;
2022-09-18 14:09:53 +00:00
unsigned int inputCoolDown = 10;
2022-09-18 12:38:00 +00:00
unsigned int sevSegCoolDown = 5000;
2022-09-16 21:17:37 +00:00
/*
* INIT
*/
void setup()
{
//debug
Serial.begin(9600);
Serial.println("setup start");
2022-09-18 12:38:00 +00:00
2022-09-21 17:18:16 +00:00
//memory
initEepromMemory();
applyMemoryChange();
//display
initSevSegDisplay();
//Init rotary encoders
rotaryEncoder.setDebounceDelay(2);
rotaryEncoder.setErrorDelay(100);
pinMode(BUTTON_Rotary, INPUT_PULLUP);
// Init keyboard output
Keyboard.begin();
//init cooldowns
lastInputMillis = millis();
Serial.println("setup complete");
playAnimation(0);
}
void initEepromMemory()
{
2022-09-18 12:38:00 +00:00
//write eeprom first init
byte memValue = EEPROM.read(0);
2022-09-21 17:18:16 +00:00
if (memValue > 0) // cannot find settings, writes default ones
2022-09-18 12:38:00 +00:00
{
for (byte i = 0; i < (sizeof(memory)/sizeof(MemSlot)); i++)
{
EEPROM.write(memory[i].address, memory[i].value);
}
2022-09-21 22:32:30 +00:00
EEPROM.write(getMemorySlot("clea")->address,0);
2022-09-18 12:38:00 +00:00
}
//read eeprom
for (byte i = 0; i < (sizeof(memory)/sizeof(MemSlot)); i++)
{
memory[i].value = EEPROM.read(memory[i].address);
}
2022-09-21 17:18:16 +00:00
}
void initSevSegDisplay()
{
2022-09-16 21:17:37 +00:00
//Init display
byte numDigits = 4;
byte digitPins[] = {7, 8, 9, 6};
byte segmentPins[] = {10, 12, 14, 16, 17, 11, 13, 15};
bool resistorsOnSegments = true;
2022-09-18 12:38:00 +00:00
//bool updateWithDelaysIn = true;
2022-09-16 21:17:37 +00:00
byte hardwareConfig = COMMON_CATHODE;
sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments);
sevseg.setBrightness(90);
2022-09-21 17:18:16 +00:00
}
2022-09-16 21:17:37 +00:00
/*
* Tick Loop
*/
void loop()
{
//animation draw tick
if (animationEnabled && animationPlaying && (millis() > (animationLastFrameMillis + animationFrameDelayMillis)))
{
drawAnimation(animationLooping);
animationLastFrameMillis = millis();
}
2022-09-16 21:17:37 +00:00
//INPUTS
2022-09-18 12:38:00 +00:00
if (millis() > lastInputMillis + inputCoolDown)
{
char customKey = keypad.getKey();
if (customKey)
{
sendInputOuput(customKey);
}
2022-09-18 14:09:53 +00:00
if (rotaryEncoder.push() == 1) // = pressed
2022-09-18 12:38:00 +00:00
{
sendInputOuput(15);
2022-09-18 14:09:53 +00:00
}
rotaryEncoderState = rotaryEncoder.rotate();
if (rotaryEncoderState == 1 || rotaryEncoderState == 2)
2022-09-18 12:38:00 +00:00
{
if ( rotaryEncoderState == 1 ) //Turned Clockwise
{
sendInputOuput(14);
}
2022-09-16 21:17:37 +00:00
2022-09-18 12:38:00 +00:00
if ( rotaryEncoderState == 2 ) //Turned Counter-Clockwise
{
sendInputOuput(13);
}
}
}
2022-09-18 14:09:53 +00:00
2022-09-21 12:12:39 +00:00
/*//clear screen after no input delay
2022-09-18 12:38:00 +00:00
if (millis() > lastInputMillis + sevSegCoolDown)
{
//sevseg.blank();
2022-09-21 12:12:39 +00:00
}*/
if(!animationPlaying && !isInMenu)
{
drawCustomSegments();
2022-09-18 12:38:00 +00:00
}
2022-09-18 14:09:53 +00:00
2022-09-18 12:38:00 +00:00
sevseg.refreshDisplay();
2022-09-16 21:17:37 +00:00
}
2022-09-18 12:38:00 +00:00
void printMenu()
{
Serial.println("printMenu");
2022-09-18 14:09:53 +00:00
Serial.print(menuCurrentPath + "/ ");
2022-09-18 12:38:00 +00:00
if (isInMenu)
{
if(menuIsSettingValue)
{
sevseg.setNumber(menuGetValue(menuCurrentItem.displayName));
Serial.println(menuGetValue(menuCurrentItem.displayName));
}
else
{
updateMenu();
sevseg.setChars(menuCurrentItem.displayName.c_str());
2022-09-18 14:09:53 +00:00
Serial.println(menuCurrentItem.displayName);
2022-09-18 12:38:00 +00:00
}
}
}
void updateMenu()
{
unsigned int correspondingPathItemIndex = 0;
for (unsigned int i = 0; i < (sizeof(menuEntries)/sizeof(MenuItem)); i++)
{
if (menuEntries[i].path == menuCurrentPath)
{
if(correspondingPathItemIndex == menuSelectionIndex)
{
menuCurrentItem = menuEntries[i];
}
correspondingPathItemIndex++;
}
}
menuCurrentPathItems = correspondingPathItemIndex;
//Serial.println(menuCurrentPathItems);
}
void menuBack()
{
if (isInMenu)
{
if (menuCurrentPath == "/" || menuCurrentPath == "" )
{
Serial.println("menuExit");
isInMenu = false;
menuSelectionIndex = 0;
menuCurrentPath = "";
2022-09-21 17:20:27 +00:00
sevseg.blank();
2022-09-21 17:18:16 +00:00
playAnimation(3);
2022-09-18 12:38:00 +00:00
}
else
{
Serial.println("menuBack");
menuSelectionIndex = menuGetSelectionIndexFromPath(menuCurrentPath);
menuCurrentPath = menuCurrentPath.substring(0,menuCurrentPath.lastIndexOf('/'));
menuIsSettingValue = false;
printMenu();
}
}
}
void menuEnter()
{
Serial.println("menuEnter");
if (isInMenu)
{
menuCurrentPath = menuCurrentItem.path + '/';
menuCurrentPath+= menuCurrentItem.displayName;
menuSelectionIndex = 0;
if (menuCurrentItem.isValue)
{
if (menuIsSettingValue)
{
for (unsigned int i = 0; i < (sizeof(memory)/sizeof(MemSlot)); i++)
{
if (memory[i].displayName == menuCurrentItem.displayName)
{
EEPROM.write(memory[i].address, memory[i].value);
Serial.println("value saved in eeprom");
menuBack();
return;
}
}
}
else
{
menuIsSettingValue = true;
Serial.println("menuIsSettingValue");
}
}
printMenu();
}
}
void menuPrev()
{
if (isInMenu)
{
if (menuIsSettingValue)
{
menuSetValue(menuCurrentItem.displayName, menuGetValue(menuCurrentItem.displayName) - 1);
}
else if (menuSelectionIndex > 0)
{
menuSelectionIndex = menuSelectionIndex - 1;
}
printMenu();
}
}
void menuNext()
{
if (isInMenu)
{
if (menuIsSettingValue)
{
menuSetValue(menuCurrentItem.displayName, menuGetValue(menuCurrentItem.displayName) + 1);
}
else if (menuSelectionIndex < menuCurrentPathItems-1)
{
menuSelectionIndex = menuSelectionIndex + 1;
}
printMenu();
}
}
byte menuGetValue(String variableName)
{
MemSlot* memorySlot = getMemorySlot(variableName);
if (memorySlot != NULL)
{
return memorySlot->value;
}
return 0;
}
bool menuSetValue(String variableName, byte newValue)
{
MemSlot* memorySlot = getMemorySlot(variableName);
if (memorySlot != NULL)
{
memorySlot->value = newValue;
2022-09-21 17:18:16 +00:00
applyMemoryChange();
2022-09-18 12:38:00 +00:00
return true;
}
return false;
}
2022-09-21 17:18:16 +00:00
void applyMemoryChange()
{
animationEnabled = (getMemorySlot("effc")->value > 0);
2022-09-21 22:32:30 +00:00
animationFrameDelayMillis = 1000 / max(1, getMemorySlot("afps")->value);
2022-09-21 17:18:16 +00:00
}
2022-09-18 12:38:00 +00:00
int menuGetSelectionIndexFromPath(String path)
{
int correspondingPathItemIndex = 0;
String makePath = "";
String parentPath = path.substring(0,path.lastIndexOf('/'));
for (unsigned int i = 0; i < (sizeof(menuEntries)/sizeof(MenuItem)); i++)
{
if (menuEntries[i].path == parentPath)
{
makePath = menuEntries[i].path + '/';
makePath += menuEntries[i].displayName;
if(makePath == path)
{
return correspondingPathItemIndex;
}
correspondingPathItemIndex++;
}
}
return 0;
}
MemSlot* getMemorySlot(String memSlotName)
{
for (unsigned int i = 0; i < (sizeof(memory)/sizeof(MemSlot)); i++)
{
if (memory[i].displayName == memSlotName)
{
return &memory[i];
}
}
return NULL;
}
void sendInputOuput(int input)
{
int numberOfModes = sizeof(modes)/(sizeof(Action)*15);
2022-09-21 22:32:30 +00:00
int currentMode = (getMemorySlot("alt")->value) % numberOfModes;
//Hardware inputs ordered from the bottom left = 1 to the top right = 12 on the switch matrix,
Action actionToRun = modes[currentMode][input-1]; //getting the virtual inputs from the modes array.
//Inputs uids starts with 1, so input - 1 to get the index 0 of the array
2022-09-21 12:12:39 +00:00
String inputName = "bt";
inputName += input;
MemSlot* buttonInputMem = getMemorySlot(inputName);
Serial.println(inputName);
if (isInMenu)
{
animationPlaying = false;
}
else
{
playAnimation(1);
2022-09-21 12:12:39 +00:00
if (buttonInputMem != NULL)
{
if (buttonInputMem->value == 1)
{
buttonsVirtualState[input-1] = !buttonsVirtualState[input-1];
}
if (buttonInputMem->value == 0)
{
buttonsVirtualState[input-1] = false;
}
}
clickKey(actionToRun.keyID, actionToRun.keyModifierID);
}
if (actionToRun.keyID == -1) //menu input, input mapping can be changed in modeAction.h
2022-09-18 12:38:00 +00:00
{
if (isInMenu)
{
menuBack();
2022-09-21 17:18:16 +00:00
//playAnimation(3);
2022-09-18 12:38:00 +00:00
}
else
{
isInMenu = true;
sevseg.blank(); // clear display
playAnimation(2);
2022-09-18 12:38:00 +00:00
printMenu();
}
}
else if (isInMenu && input == 13) //menu prev, hardcoded input
2022-09-18 12:38:00 +00:00
{
menuPrev();
}
else if (isInMenu && input == 14) //menu next, hardcoded input
2022-09-18 12:38:00 +00:00
{
menuNext();
}
else if (isInMenu && input == 15) //menu enter, hardcoded input
2022-09-18 12:38:00 +00:00
{
menuEnter();
}
lastInputMillis = millis();
2022-09-18 12:38:00 +00:00
}
2022-09-18 14:09:53 +00:00
void clickKey(int key, int modifier)
{
Keyboard.set_modifier(modifier);
2022-09-18 14:09:53 +00:00
Keyboard.press(key);
Keyboard.release(key);
Keyboard.set_modifier(0);
//Keyboard.send_now(); //can't remember what's that's for
}
void playAnimation(int animID)
{
if (animationEnabled)
{
currentAnimationID = animID;
animationFrame = 0;
animationPlaying = true;
}
}
void drawAnimation(bool looping)
{
int currentAnimationFrameTotal = animData[currentAnimationID].animationFrameCount;
sevseg.setSegments(animData[currentAnimationID].animationPtr + (animationFrame * (sizeof(const uint8_t)*4)));
animationFrame++;
if (animationFrame == currentAnimationFrameTotal)
{
animationFrame = 0;
if (!looping)
{
animationPlaying = false;
sevseg.blank();
if (isInMenu) //not great
{
printMenu();
}
}
}
2022-09-18 14:09:53 +00:00
}
2022-09-21 12:12:39 +00:00
void drawCustomSegments()
{
uint8_t seg0 = (0b00001000 * buttonsVirtualState[0]) + (0b01000000 * buttonsVirtualState[4]) + (0b00000001 * buttonsVirtualState[8]);
uint8_t seg1 = (0b00001000 * buttonsVirtualState[1]) + (0b01000000 * buttonsVirtualState[5]) + (0b00000001 * buttonsVirtualState[9]);
uint8_t seg2 = (0b00001000 * buttonsVirtualState[2]) + (0b01000000 * buttonsVirtualState[6]) + (0b00000001 * buttonsVirtualState[10]);
uint8_t seg3 = (0b00001000 * buttonsVirtualState[3]) + (0b01000000 * buttonsVirtualState[7]) + (0b00000001 * buttonsVirtualState[11]);
sevseg.setSegmentsDigit(0,seg0);
sevseg.setSegmentsDigit(1,seg1);
sevseg.setSegmentsDigit(2,seg2);
sevseg.setSegmentsDigit(3,seg3);
}