Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

groveRGBLCD: Add support for I2C Grove RGB LCD #331

Merged
merged 1 commit into from
Nov 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,10 @@ https://github.com/neu-rah/AnsiStream

- Unix terminal

**Grove RGB LCD I2C 2x16**

https://wiki.seeedstudio.com/Grove-LCD_RGB_Backlight/

**Web browser**

- ESP8266 (builtin)
Expand Down
207 changes: 207 additions & 0 deletions examples/GroveRGB/GroveRGB/GroveRGB.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
#include <Arduino.h>

/********************
Sept. 2014 Rui Azevedo - ruihfazevedo(@rrob@)gmail.com
Nov. 2020 Graham Whaley - adapted to Grove RGB LCD

menu output to Grove RGB LCD I2C
output: GROVERGBLCD : https://wiki.seeedstudio.com/Grove-LCD_RGB_Backlight/
input: click encoder and Serial
board: PJRC Teensy 4.0 : https://www.pjrc.com/store/teensy40.html
***/

#include <Wire.h>
#include <menu.h>
#include <menuIO/groveRGBLCDOut.h>
#include <menuIO/serialOut.h>
#include <menuIO/serialIn.h>
#include <menuIO/clickEncoderIn.h>
#include <menuIO/chainStream.h>

using namespace Menu;

// LCD, standard Grove I2C devices /////////////
rgb_lcd lcd;

// Encoder /////////////////////////////////////
#define encA 3
#define encB 2
//this encoder has a button here
#define encBtn 4

ClickEncoder clickEncoder(encA,encB,encBtn,2);
ClickEncoderStream encStream(clickEncoder,1);

//input from the clickencoder + serial
serialIn serial(Serial);
menuIn* inputsList[]={&encStream,&serial};
chainStream<2> in(inputsList);//3 is the number of inputs

#define LEDPIN LED_BUILTIN //Teensy 4.0 LED pin

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

MENU(mainMenu,"Main menu",doNothing,noEvent,wrapStyle
,OP("Op1",action1,anyEvent)
,OP("Op2",action2,enterEvent)
//,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
,GROVERGBLCD_OUT(lcd, {0, 0, 16, 2})
,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;
}

void setup() {
pinMode(encBtn,INPUT_PULLUP);
pinMode(LEDPIN,OUTPUT);
Serial.begin(115200);
while(!Serial);
Serial.println("Arduino Menu Library");Serial.flush();

lcd.begin(16,2);
lcd.setRGB(32, 32, 32);
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");
delay(2000);
}

void loop() {
clickEncoder.service();
nav.poll();
digitalWrite(LEDPIN, ledCtrl);
delay(100);//simulate a delay as if other tasks are running
}
7 changes: 7 additions & 0 deletions src/macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
#define ANSISERIAL_OUT(...) ON(ANSISERIAL_OUT,__COUNTER__,__VA_ARGS__)
#define LIQUIDCRYSTAL_OUT(...) ON(LIQUIDCRYSTAL_OUT,__COUNTER__,__VA_ARGS__)
#define LCD_OUT(...) ON(LCD_OUT,__COUNTER__,__VA_ARGS__)
#define GROVERGBLCD_OUT(...) ON(GROVERGBLCD_OUT,__COUNTER__,__VA_ARGS__)
#define ADAGFX_OUT(...) ON(ADAGFX_OUT,__COUNTER__,__VA_ARGS__)
#define TFT_eSPI_OUT(...) ON(TFT_eSPI_OUT,__COUNTER__,__VA_ARGS__)
#define TFT_OUT(...) ON(TFT_OUT,__COUNTER__,__VA_ARGS__)
Expand Down Expand Up @@ -123,6 +124,11 @@ Menu::idx_t id##Tops##n[md];\
PANELS(id##Panels##n,__VA_ARGS__);\
Menu::lcdOut id##n(&device,id##Tops##n,id##Panels##n);

#define VAR_GROVERGBLCD_OUT(id,md,n,device,...)\
Menu::idx_t id##Tops##n[md];\
PANELS(id##Panels##n,__VA_ARGS__);\
Menu::grovergblcdOut id##n(&device,id##Tops##n,id##Panels##n);

#define VAR_ADAGFX_OUT(id,md,n,gfx,color,fontW,fontH,...)\
Menu::idx_t id##Tops##n[md];\
PANELS(id##Panels##n,__VA_ARGS__);\
Expand Down Expand Up @@ -173,6 +179,7 @@ Menu::utftOut id##n(gfx,color,id##Tops##n,id##Panels##n,fontW,fontH);
#define REF_ANSISERIAL_OUT(id,md,n,...) &id##n,
#define REF_LIQUIDCRYSTAL_OUT(id,md,n,...) &id##n,
#define REF_LCD_OUT(id,md,n,...) &id##n,
#define REF_GROVERGBLCD_OUT(id,md,n,...) &id##n,
#define REF_ADAGFX_OUT(id,md,n,...) &id##n,
#define REF_TFT_eSPI_OUT(id,md,n,...) &id##n,
#define REF_U8GLIB_OUT(id,md,n,...) &id##n,
Expand Down
52 changes: 52 additions & 0 deletions src/menuIO/groveRGBLCDOut.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* -*- C++ -*- */

//for using the Grove 2x16 RGB LCD i2c
// https://wiki.seeedstudio.com/Grove-LCD_RGB_Backlight/
// https://github.com/Seeed-Studio/Grove_LCD_RGB_Backlight
// Uses default I2C device addresses on default I2C bus

#ifndef RSITE_ARDUINO_MENU_GROVERGBLCDOUT
#define RSITE_ARDUINO_MENU_GROVERGBLCDOUT

#ifndef ARDUINO_SAM_DUE
#include "../menuDefs.h"
#include <Wire.h>
#include <rgb_lcd.h>

namespace Menu {

class grovergblcdOut:public cursorOut {
public:
rgb_lcd* device;
inline grovergblcdOut(rgb_lcd* o,idx_t *t,panelsList &p,menuOut::styles s=menuOut::minimalRedraw)
:cursorOut(t,p,s),device(o) {}
size_t write(uint8_t ch) override {return device->write(ch);}
void clear() override {
device->clear();
panels.reset();
}
void setCursor(idx_t x,idx_t y,idx_t panelNr=0) override {
const panel p=panels[panelNr];
device->setCursor(p.x+x,p.y+y);
}
idx_t startCursor(navRoot& root,idx_t x,idx_t y,bool charEdit,idx_t panelNr=0) override {return 0;}
idx_t endCursor(navRoot& root,idx_t x,idx_t y,bool charEdit,idx_t panelNr=0) override {return 0;}
idx_t editCursor(navRoot& root,idx_t x,idx_t y,bool editing,bool charEdit,idx_t panelNr=0) override {
trace(MENU_DEBUG_OUT<<"lcdOut::editCursor "<<x<<","<<y<<endl);
//text editor cursor
device->noBlink();
device->noCursor();
if (editing) {
device->setCursor(x, y);
if (charEdit) device->cursor();
else device->blink();
}
return 0;
}

};

}//namespace Menu

#endif
#endif