#include <Arduino.h>
#include <DS3232RTC.h>
/********************
Sept. 2014 Rui Azevedo - ruihfazevedo(@rrob@)gmail.com
menu output to standard arduino LCD (LiquidCrystal)
output: LCD
input: encoder and Serial
www.r-site.net
***/
#include <Wire.h>
#include <menu.h>
#include <menuIO/liquidCrystalOutI2C.h>
#include <menuIO/serialOut.h>
#include <menuIO/serialIn.h>
//#include <menuIO/encoderIn.h>
#include <menuIO/keyIn.h>
#include <menuIO/analogAxisIn.h>
#include <menuIO/chainStream.h>
using namespace Menu;
// LCD /////////////////////////////////////////
#define RS 8
#define RW 3
#define EN 9
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Joystick
const byte PIN_JOY_VRX = A0;
const byte PIN_JOY_VRY = A1;
const byte PIN_JOY_SW = 7;
// Encoder /////////////////////////////////////
#define encA A2
#define encB A1
//this encoder has a button here
#define encBtn A3
DS3232RTC rtc;
//encoderIn<encA,encB> encoder;//simple quad encoder driver
//encoderInStream<encA,encB> encStream(encoder,4);// simple quad encoder fake Stream
//a keyboard with only one key as the encoder button
//keyMap encBtn_map[]={{-encBtn,defaultNavCodes[enterCmd].ch}};//negative pin numbers use internal pull-up, this is on when low
//keyIn<1> encButton(encBtn_map);//1 is the number of keys
analogAxis<PIN_JOY_VRY,10,false> ay;
keyMap btnsMap[]={{-PIN_JOY_SW,defaultNavCodes[enterCmd].ch}};//negative pin numbers use internal pull-up, this is on when low
keyIn<1> btns(btnsMap);// 1 is the number of keys
//input from the encoder + encoder button + serial
// serialIn serial(Serial);
// menuIn* inputsList[]={&serial};
// chainStream<3> in(inputsList);//3 is the number of inputs
MENU_INPUTS(in,&ay,&btns);
#define LEDPIN 13
result doAlert(eventMask e, prompt &item);
result showEvent(eventMask e,navNode& nav,prompt& item) {
Serial.print("event: ");
Serial.println(e);
return proceed;
}
int test=55;
result action1(eventMask e,navNode& nav, prompt &item) {
Serial.print("action1 event: ");
Serial.print(e);
Serial.println(", proceed menu");
Serial.flush();
return proceed;
}
result action2(eventMask e,navNode& nav, prompt &item) {
Serial.print("action2 event: ");
Serial.print(e);
Serial.print(", quiting menu.");
Serial.flush();
return quit;
}
int ledCtrl=LOW;
result myLedOn() {
ledCtrl=HIGH;
return proceed;
}
result myLedOff() {
ledCtrl=LOW;
return proceed;
}
TOGGLE(ledCtrl,setLed,"Led: ",doNothing,noEvent,noStyle//,doExit,enterEvent,noStyle
,VALUE("On",HIGH,doNothing,noEvent)
,VALUE("Off",LOW,doNothing,noEvent)
);
int selTest=0;
SELECT(selTest,selMenu,"Select",doNothing,noEvent,noStyle
,VALUE("Zero",0,doNothing,noEvent)
,VALUE("One",1,doNothing,noEvent)
,VALUE("Two",2,doNothing,noEvent)
);
int chooseTest=-1;
CHOOSE(chooseTest,chooseMenu,"Choose",doNothing,noEvent,noStyle
,VALUE("First",1,doNothing,noEvent)
,VALUE("Second",2,doNothing,noEvent)
,VALUE("Third",3,doNothing,noEvent)
,VALUE("Last",-1,doNothing,noEvent)
);
//customizing a prompt look!
//by extending the prompt class
class altPrompt:public prompt {
public:
altPrompt(constMEM promptShadow& p):prompt(p) {}
Used printTo(navRoot &root,bool sel,menuOut& out, idx_t idx,idx_t len,idx_t) override {
return out.printRaw(F("special prompt!"),len);;
}
};
MENU(subMenu,"Sub-Menu",showEvent,anyEvent,noStyle
,OP("Sub1",showEvent,anyEvent)
,OP("Sub2",showEvent,anyEvent)
,OP("Sub3",showEvent,anyEvent)
,altOP(altPrompt,"",showEvent,anyEvent)
,EXIT("<Back")
);
/*extern menu mainMenu;
TOGGLE((mainMenu[1].enabled),togOp,"Op 2:",doNothing,noEvent,noStyle
,VALUE("Enabled",enabledStatus,doNothing,noEvent)
,VALUE("disabled",disabledStatus,doNothing,noEvent)
);*/
// char* constMEM hexDigit MEMMODE="0123456789ABCDEF";
// char* constMEM hexNr[] MEMMODE={"0","x",hexDigit,hexDigit};
// char buf1[]="0x11";
tmElements_t tm_time;
uint16_t my_year=1900;
//uint8_t my_month=10;
//uint8_t my_day=7;
//uint16_t my_hrs=0;
//uint16_t my_mins=0;
//define a pad style menu (single line menu)
//here with a set of fields to enter a date in YYYY/MM/DD format
altMENU(menu,timeMenu,"T",doNothing,noEvent,noStyle,(systemStyles)(_asPad|Menu::_menuData|Menu::_canNav|_parentDraw)
,FIELD(tm_time.Hour,"",":",0,11,1,0,doDateTime,updateEvent,noStyle)
,FIELD(tm_time.Minute,"","",0,59,10,1,doDateTime,updateEvent,wrapStyle)
);
//define a pad style menu (single line menu)
//here with a set of fields to enter a date in YYYY/MM/DD format
altMENU(menu,dateMenu,"D",doDateTime,updateEvent,noStyle,(systemStyles)(_asPad|Menu::_menuData|Menu::_canNav|_parentDraw)
,FIELD(tm_time.Day,"",".",1,31,10,1,doDateTime,updateEvent,noStyle)
,FIELD(tm_time.Month,"","",1,12,1,0,doDateTime,updateEvent,wrapStyle)
,FIELD(my_year,"","",1970,3000,20,1,doDateTime,updateEvent,wrapStyle)
);
MENU(mainMenu,"Main menu",doNothing,noEvent,wrapStyle
,OP("Op1",action1,anyEvent)
,OP("Op2",action2,enterEvent)
,SUBMENU(dateMenu)
,SUBMENU(timeMenu)
//,SUBMENU(togOp)
,FIELD(test,"Test","%",0,100,10,1,doNothing,noEvent,wrapStyle)
,SUBMENU(subMenu)
,SUBMENU(setLed)
,OP("LED On",myLedOn,enterEvent)
,OP("LED Off",myLedOff,enterEvent)
,SUBMENU(selMenu)
,SUBMENU(chooseMenu)
,OP("Alert test",doAlert,enterEvent)
// ,EDIT("Hex",buf1,hexNr,doNothing,noEvent,noStyle)
,EXIT("<Back")
);
//const panel panels[] MEMMODE={{0,0,16,2}};
//navNode* nodes[sizeof(panels)/sizeof(panel)];
//panelsList pList(panels,nodes,1);
#define MAX_DEPTH 2
/*idx_t tops[MAX_DEPTH];
liquidCrystalOut outLCD(lcd,tops,pList);//output device for LCD
menuOut* constMEM outputs[] MEMMODE={&outLCD};//list of output devices
outputsList out(outputs,1);//outputs list with 2 outputs*/
MENU_OUTPUTS(out, MAX_DEPTH
,LIQUIDCRYSTAL_OUT(lcd,{0,0,20,4})
//,SERIAL_OUT(serial)
,NONE
);
NAVROOT(nav,mainMenu,MAX_DEPTH,in,out);//the navigation root object
result alert(menuOut& o,idleEvent e) {
if (e==idling) {
o.setCursor(0,0);
o.print("alert test");
o.setCursor(0,1);
o.print("[select] to continue...");
}
return proceed;
}
result doAlert(eventMask e, prompt &item) {
nav.idleOn(alert);
return proceed;
}
result idle(menuOut& o,idleEvent e) {
switch(e) {
case idleStart:o.print("suspending menu!");break;
case idling:o.print("suspended...");break;
case idleEnd:o.print("resuming menu.");break;
}
return proceed;
}
result doDateTime(eventMask e, prompt &item) {
rtc_set_from_settings();
return proceed;
}
void rtc_set_from_settings(){
tm_time.Year = CalendarYrToTm(my_year);
rtc.set(makeTime(tm_time));
Serial.println(day(rtc.get()));
Serial.println(month(rtc.get()));
Serial.println(year(rtc.get()));
}
void rtc_get_to_settings(){
breakTime(rtc.get(), tm_time);
my_year = tmYearToCalendar(tm_time.Year);
}
void setup() {
pinMode(encBtn,INPUT_PULLUP);
pinMode(PIN_JOY_SW,INPUT_PULLUP);
pinMode(LEDPIN,OUTPUT);
Serial.begin(115200);
while(!Serial);
Serial.println("Arduino Menu Library");Serial.flush();
// encoder.begin();
lcd.begin(20,4);
// nav.idleTask=idle;//point a function to be used when menu is suspended
// mainMenu[1].enabled=disabledStatus;
nav.showTitle=false;
lcd.setCursor(0, 0);
lcd.print("Menu 4.x LCD");
lcd.setCursor(0, 1);
lcd.print("r-site.net");
Serial.println(day(rtc.get()));
Serial.println(month(rtc.get()));
Serial.println(year(rtc.get()));
rtc_get_to_settings();
Serial.println("tm_time");
Serial.println(tm_time.Day);
Serial.println(tm_time.Month);
Serial.println(tm_time.Year);
//delay(2000);
}
void loop() {
nav.poll();
delay(100);//simulate a delay as if other tasks are running
}