// LCD1602 and Pi Pico!
#include <LiquidCrystal.h>
#include "RTClib.h"
RTC_DS1307 rtc;
bool setSDA(4);
bool setSCL(5);
#define CLK 2
#define DT 3
#define SELECT 6
int lastClk = HIGH;
int lastSwPos = LOW;
int menuPos = 0;
int numLines = 0;
bool isSubMenu = false;
int currentLine = 0;
char receivedChar;
boolean newData = false;
boolean hasRowsAbove = false;
int globalOffset = 0;
int actualRowNum = 0;
boolean isInDebug = false;
boolean isLoggerEnabled = false;
// Custom Chars
byte arrow[] = {
0b00000,
0b00100,
0b00110,
0b11111,
0b11111,
0b00110,
0b00100,
0b00000
};
byte downArrow[] = {
0b00100,
0b00100,
0b00100,
0b00100,
0b00100,
0b11111,
0b01110,
0b00100
};
// menus
/*
Each menu needs the follwoing:
Name (variable name)
If its a sub menu ("t" or "f")
Num of Items
items (Must be greater than 1)
Each item needs the following:
Title (Must be less than 18)
action or menu (written as "a" or "m")
pointer to either a function or an array
*/
String mainMenu[][3] = {{"f"}, {"6"}, {"Test", "a", "00"}, {"Hello World", "a", "01"}, {"Production", "a", "02"}, {"Hi Lucas", "a", "03"}, {"Womp Womp", "a", "04"}, {"Shut Down", "a", "05"}};
LiquidCrystal lcd(12, 11, 10, 9, 8, 13); // rs, enable, d4, d5, d6, d7
void setup() {
setupLCD("0.1");
Serial.begin(115200);
Serial.println("HillMapper v0.1, Developed by MrPurpleSocks");
pinMode(CLK, INPUT);
pinMode(DT, INPUT);
pinMode(SELECT, INPUT_PULLUP);
Serial.println("initilization finished");
delay(2000);
clearLCD();
Serial.println("LCD Cleared, entering loop");
Serial.println("press D to enter debug");
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1) delay(10);
}
if (! rtc.isrunning()) {
Serial.println("RTC is NOT running, let's set the time!");
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
displayMenu(0, mainMenu);
}
void loop() {
delay(1); // Adding a delay() here speeds up the simulation
int action = checkEncoder();
switch (action) {
case 1:
cursorDown();
break;
case 2:
cursorUp();
break;
case 3:
clearLCD();
Serial.println("clicked");
Serial.println(globalOffset);
getAction(mainMenu[actualRowNum + 2][2].toInt());
break;
default:
break;
}
lcd.noBlink();
if (!isInDebug){
if (Serial.available() > 0) {
receivedChar = Serial.read();
newData = true;
}
if (newData) {
if (receivedChar == 'D') {
isInDebug = true;
Serial.println("Succesfully entered dubug!");
Serial.println("PRPL Debugger v1.0");
Serial.println("Enter L to enable Logger");
}
}
}
if (isInDebug) {
if(!isLoggerEnabled) {
if (Serial.available() > 0) {
receivedChar = Serial.read();
newData = true;
}
if (newData) {
if (receivedChar == 'L') {
isInDebug = true;
Serial.println("Succesfully enabled logger");
Serial.println("oops i forgot to add that");
}
}
}
}
}
void cursorUp(){
if (currentLine <= 0) {
if(numLines > 4) {
if(actualRowNum == 0){
globalOffset = numLines - 4;
actualRowNum = numLines - 1;
currentLine = 3;
displayMenu(globalOffset, mainMenu);
lcd.setCursor(0, 0);
lcd.write(" ");
currentLine = 3; // I didnt think that would work...
lcd.setCursor(0, currentLine);
lcd.write("*");
return;
}
globalOffset--;
displayMenu(globalOffset, mainMenu);
actualRowNum--;
return;
}
lcd.setCursor(0, currentLine);
lcd.write(" ");
currentLine = 3; // I didnt think that would work...
lcd.setCursor(0, currentLine);
lcd.write("*");
actualRowNum--;
return;
}
lcd.setCursor(0, currentLine);
lcd.write(" ");
currentLine--;
actualRowNum--;
lcd.setCursor(0, currentLine);
lcd.write("*");
return;
}
void cursorDown(){
if (currentLine >= 3) {
if(numLines > 4) {
if(actualRowNum == numLines - 1){
globalOffset = 0;
actualRowNum = 0;
currentLine = 0;
displayMenu(globalOffset, mainMenu);
return;
}
globalOffset++;
displayMenu(globalOffset, mainMenu);
actualRowNum++;
lcd.setCursor(0, 0);
lcd.write(" ");
lcd.setCursor(0, 3);
currentLine = 3;
lcd.write("*");
return;
}
lcd.setCursor(0, currentLine);
lcd.write(" ");
currentLine = -1; // I didnt think that would work...
lcd.setCursor(0, currentLine);
lcd.write("*");
actualRowNum++;
return;
}
lcd.setCursor(0, currentLine);
lcd.write(" ");
currentLine++;
actualRowNum++;
lcd.setCursor(0, currentLine);
lcd.write("*");
return;
}
void displayMenu(int offset, String menu[][3]){
clearLCD();
if (menu[0][0] == "t"){
isSubMenu = false;
}
if (menu[0][0] == "f"){
isSubMenu = true;
}
numLines = menu[1][0].toInt();
for (int i = 0; i < 4; i++){
lcd.setCursor(1, i);
lcd.print(" " + menu[i+2+offset][0]);
lcd.setCursor(19, i);
lcd.write(byte(0));
}
lcd.setCursor(0,0);
lcd.write("*");
}
void setupLCD(String version){
lcd.begin(20, 4);
lcd.createChar(0, arrow);
lcd.createChar(1, downArrow);
printCentered("Purple HillMapper", 1);
printCentered("> v0.0 <", 2);
lcd.noBlink();
}
void clearLine(int line) {
lcd.setCursor(0, line);
lcd.print(" ");
}
void clearLCD() {
clearLine(0);
clearLine(1);
clearLine(2);
clearLine(3);
}
void printCentered(String text, int line){
int offset = (20 - text.length()) / 2;
lcd.setCursor(offset, line);
lcd.print(text);
}
int checkEncoder(){
int newClk = digitalRead(CLK);
if (newClk != lastClk) {
lastClk = newClk;
int dtValue = digitalRead(DT);
if (newClk == LOW && dtValue == HIGH) {
return 1;
}
if (newClk == LOW && dtValue == LOW) {
return 2;
}
int swPos = digitalRead(SELECT);
}
if (digitalRead(SELECT) == LOW){
return 3;
}
return 0;
}
void test(){
printCentered("Balls", 2);
delay(1000);
displayMenu(0, mainMenu);
}
void actionError(String error){
clearLCD();
printCentered("ERR ACTION NOT FOUND", 0);
lcd.setCursor(0, 1);
//lcd.print(error);
printCentered("WOMP WOMP",1);
printCentered("i no work owie :(",3);
}
void helloWorld(){
Serial.println("huh 2");
clearLCD();
printCentered("Hello World!", 0);
delay(1000);
}
// Depricated: function provided by RTCLib Library
void getTime(){
DateTime dt = rtc.now();
Serial.println(String(dt.timestamp(DateTime::TIMESTAMP_FULL)));
}
void debugMessage(String function, String message) {
if (isInDebug) {
DateTime dt = rtc.now();
Serial.println(String(dt.timestamp(DateTime::TIMESTAMP_FULL)) + " " + function + "() - " + message);
}
}
void getAction(int actionNum){
// I hate it, but it probably works (update: nvm it doesnt)
debugMessage("getAction", "Menu " + actionNum);
switch (actionNum) {
case 0:
test();
return;
case 1:
debugMessage("getAction()->helloWorld", "Entering Hello World function");
helloWorld();
return;
case 5:
return;
default:
actionError("");
return;
}
}