From 5dc64697ced34fc2978c43bdbd5805ac279b1680 Mon Sep 17 00:00:00 2001 From: Rui Azevedo Date: Tue, 11 Sep 2018 17:18:54 +0000 Subject: [PATCH 001/197] fix liquidcrystal example --- examples/LCDs/LiquidCrystal/LiquidCrystal/LiquidCrystal.ino | 1 + library.properties | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/LCDs/LiquidCrystal/LiquidCrystal/LiquidCrystal.ino b/examples/LCDs/LiquidCrystal/LiquidCrystal/LiquidCrystal.ino index 2b01c045..b82a223a 100644 --- a/examples/LCDs/LiquidCrystal/LiquidCrystal/LiquidCrystal.ino +++ b/examples/LCDs/LiquidCrystal/LiquidCrystal/LiquidCrystal.ino @@ -9,6 +9,7 @@ input: encoder and Serial www.r-site.net ***/ +#include #include #include #include diff --git a/library.properties b/library.properties index 02df494b..e15f6b71 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ArduinoMenu library -version=4.13.2 +version=4.13.1 author=Rui Azevedo, ruihfazevedo@gmail.com maintainer=neu-rah, ruihfazevedo@gmail.com sentence=Generic menu/interactivity system From 7dd939baf855c7e5f7d9fff385b60baf83127132 Mon Sep 17 00:00:00 2001 From: Rui Azevedo Date: Tue, 11 Sep 2018 17:19:10 +0000 Subject: [PATCH 002/197] version bump --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index e15f6b71..2beb0ea0 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ArduinoMenu library -version=4.13.1 +version=4.13.3 author=Rui Azevedo, ruihfazevedo@gmail.com maintainer=neu-rah, ruihfazevedo@gmail.com sentence=Generic menu/interactivity system From ab7b4f9517c39ca74410e595d733ea905caf8867 Mon Sep 17 00:00:00 2001 From: Rui Azevedo Date: Wed, 12 Sep 2018 15:55:57 +0000 Subject: [PATCH 003/197] simplify example --- .../LCDs/LiquidCrystal/LiquidCrystal/LiquidCrystal.ino | 8 ++++---- library.properties | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/LCDs/LiquidCrystal/LiquidCrystal/LiquidCrystal.ino b/examples/LCDs/LiquidCrystal/LiquidCrystal/LiquidCrystal.ino index b82a223a..e9fe9fc1 100644 --- a/examples/LCDs/LiquidCrystal/LiquidCrystal/LiquidCrystal.ino +++ b/examples/LCDs/LiquidCrystal/LiquidCrystal/LiquidCrystal.ino @@ -127,9 +127,9 @@ TOGGLE((mainMenu[1].enabled),togOp,"Op 2:",doNothing,noEvent,noStyle ,VALUE("disabled",disabledStatus,doNothing,noEvent) );*/ -char* constMEM hexDigit MEMMODE="0123456789ABCDEF"; -char* constMEM hexNr[] MEMMODE={"0","x",hexDigit,hexDigit}; -char buf1[]="0x11"; +// 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) @@ -143,7 +143,7 @@ MENU(mainMenu,"Main menu",doNothing,noEvent,wrapStyle ,SUBMENU(selMenu) ,SUBMENU(chooseMenu) ,OP("Alert test",doAlert,enterEvent) - ,EDIT("Hex",buf1,hexNr,doNothing,noEvent,noStyle) + // ,EDIT("Hex",buf1,hexNr,doNothing,noEvent,noStyle) ,EXIT(" Date: Thu, 20 Sep 2018 17:30:47 +0300 Subject: [PATCH 004/197] Basic support for pcf8574 i2c keypad --- src/menuIO/I2CkeypadIn.h | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/menuIO/I2CkeypadIn.h diff --git a/src/menuIO/I2CkeypadIn.h b/src/menuIO/I2CkeypadIn.h new file mode 100644 index 00000000..2c1af319 --- /dev/null +++ b/src/menuIO/I2CkeypadIn.h @@ -0,0 +1,43 @@ +/* -*- C++ -*- */ +/************** +Jan. 2018 Rui Azevedo - ruihfazevedo(@rrob@)gmail.com + +I2C keypad driver +using + https://github.com/whatnick/i2ckeypad + + Note: you may be need to adjust keypad-to-pcf8574 pin mappings and keymap in i2ckeypad.cpp for your specific keypad. + +***/ + +#ifndef RSITE_I2CKEYPAD_DEF_H + #define RSITE_I2CKEYPAD_DEF_H + #include "../menuDefs.h" + + #include + namespace Menu { + + class I2CkeypadIn:public menuIn { + public: + char key=0; + i2ckeypad * in; + I2CkeypadIn(i2ckeypad * in):in(in) {} + int available(void) { + return peek()!=0; + } + int peek(void) { + return key != 0 ? key : (key=in->get_key()) ?key : 0; + } + int read() { + if (key != 0) { + char k=key; + key=0; + return k; + } + return available()?read():0; + } + void flush() {} + size_t write(uint8_t v) {return 0;} + }; + }; +#endif From c29bf07c5a95c9078a2c90998ca6cb4fb30c7875 Mon Sep 17 00:00:00 2001 From: Rui Azevedo Date: Thu, 20 Sep 2018 16:13:35 +0000 Subject: [PATCH 005/197] version bump remove ansiSerial example from travis tests as it needs streamflow and it is not registered on pplatformio --- .travis.yml | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 11c772a8..05a85f11 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ cache: env: - PLATFORMIO_CI_SRC=examples/Blink/Blink/Blink.ino - PLATFORMIO_CI_SRC=examples/Serial/serialio/serialio/serialio.ino - - PLATFORMIO_CI_SRC=examples/Serial/ansiSerial/ansiSerial/ansiSerial.ino + # - PLATFORMIO_CI_SRC=examples/Serial/ansiSerial/ansiSerial/ansiSerial.ino - PLATFORMIO_CI_SRC=examples/codeCtrl/codeCtrl/codeCtrl.ino - PLATFORMIO_CI_SRC=examples/adafruitGfx/lcdMono/lcdMono/lcdMono.ino - PLATFORMIO_CI_SRC=examples/adafruitGfx/tft/tft/tft.ino diff --git a/library.properties b/library.properties index 916b95bc..0ca23686 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ArduinoMenu library -version=4.13.4 +version=4.14.0 author=Rui Azevedo, ruihfazevedo@gmail.com maintainer=neu-rah, ruihfazevedo@gmail.com sentence=Generic menu/interactivity system From 5d8b41a5ab905a5462f3ae9987f26d84d63bca85 Mon Sep 17 00:00:00 2001 From: Rui Azevedo Date: Thu, 20 Sep 2018 16:23:31 +0000 Subject: [PATCH 006/197] update readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c520eb55..38c7f94c 100644 --- a/README.md +++ b/README.md @@ -261,6 +261,9 @@ Matrix keypad http://playground.arduino.cc/Code/Keypad https://github.com/Nullkraft/Keypad +PCF8574 based i2c matrix keypad +https://github.com/whatnick/i2ckeypad + User defined input calling menu navigation API Web browser (experimental) when using ESP devices From d8e9685036ce690b3c1f25447fd3f34982808307 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 12 Oct 2018 14:18:28 +0300 Subject: [PATCH 007/197] Added support for UART Displays by Surenoo --- src/macros.h | 7 ++ src/menuIO/uartOut.h | 168 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 src/menuIO/uartOut.h diff --git a/src/macros.h b/src/macros.h index 91e1fd71..4b3e7d1d 100644 --- a/src/macros.h +++ b/src/macros.h @@ -82,6 +82,7 @@ #define TFT_OUT(...) ON(TFT_OUT,__COUNTER__,__VA_ARGS__) #define U8GLIB_OUT(...) ON(U8GLIB_OUT,__COUNTER__,__VA_ARGS__) #define U8G2_OUT(...) ON(U8G2_OUT,__COUNTER__,__VA_ARGS__) +#define UART_OUT(...) ON(UART_OUT,__COUNTER__,__VA_ARGS__) #define UCG_OUT(...) ON(UCG_OUT,__COUNTER__,__VA_ARGS__) #define U8X8_OUT(...) ON(U8X8_OUT,__COUNTER__,__VA_ARGS__) #define UTFT_OUT(...) ON(UTFT_OUT,__COUNTER__,__VA_ARGS__) @@ -130,6 +131,11 @@ Menu::idx_t id##Tops##n[md];\ PANELS(id##Panels##n,__VA_ARGS__);\ Menu::u8g2Out id##n(gfx,color,id##Tops##n,id##Panels##n,fontW,fontH,offsetX,offsetY); +#define VAR_UART_OUT(id,md,n,gfx,color,font,offsetX,offsetY,...)\ +Menu::idx_t id##Tops##n[md];\ +PANELS(id##Panels##n,__VA_ARGS__);\ +Menu::uartOut id##n(gfx,color,id##Tops##n,id##Panels##n,font,offsetX,offsetY); + #define VAR_UCG_OUT(id,md,n,gfx,color,fontW,fontH,offsetX,offsetY,...)\ Menu::idx_t id##Tops##n[md];\ PANELS(id##Panels##n,__VA_ARGS__);\ @@ -153,6 +159,7 @@ Menu::utftOut id##n(gfx,color,id##Tops##n,id##Panels##n,fontW,fontH); #define REF_ADAGFX_OUT(id,md,n,...) &id##n, #define REF_U8GLIB_OUT(id,md,n,...) &id##n, #define REF_U8G2_OUT(id,md,n,...) &id##n, +#define REF_UART_OUT(id,md,n,...) &id##n, #define REF_UCG_OUT(id,md,n,...) &id##n, #define REF_U8X8_OUT(id,md,n,...) &id##n, #define REF_UTFT_OUT(id,md,n,...) &id##n, diff --git a/src/menuIO/uartOut.h b/src/menuIO/uartOut.h new file mode 100644 index 00000000..eccf0525 --- /dev/null +++ b/src/menuIO/uartOut.h @@ -0,0 +1,168 @@ +/* -*- C++ -*- */ + +/******************** +Oct. 2016 Stephen Denne https://github.com/datacute +Based on U8GLibOut.h from Rui Azevedo - ruihfazevedo(@rrob@)gmail.com +Original from: https://github.com/christophepersoz + +Use graphics screens as menu output, based on U8G2 graphic display +www.r-site.net + +***/ +#ifndef RSITE_ARDUINOP_MENU_UART +#define RSITE_ARDUINOP_MENU_UART +#include "menuDefs.h" + +namespace Menu { + +class uartOut:public gfxOut { + public: + enum systemFont { + font16 = 16, + font24 = 24, + font32 = 32 + }; + int8_t offsetX=0; + int8_t offsetY=0; + int cursorX = 0; + int cursorY = 0; + char buf[100]; + int currentColor = 0; + int m_bgColor = 0; + systemFont m_Font; + Stream& stream; + const colorDef (&colors)[nColors]; + uartOut( + Stream& stream, + const colorDef (&c)[nColors], + idx_t* t, + panelsList &p, + systemFont font = font24, + idx_t offsetX=0, + idx_t offsetY=0, + int fontMarginY=1 + ) :gfxOut(font/2,font,t,p,(styles)(menuOut::redraw|menuOut::rasterDraw)),stream(stream),colors(c) + { + this->offsetX=offsetX; + this->offsetY=offsetY; + this->fontMarginY=fontMarginY; + this->m_Font = font; + } + + size_t write(uint8_t ch) override + { + sprintf(buf,"SBC(%d);DCV%d(%d,%d,'%c',%d);", m_bgColor, m_Font, cursorX, cursorY - resY + fontMarginY, (char)ch, currentColor); + sendCommand(buf); + cursorX = cursorX + resX; + return 1; + } + + inline uint8_t getColor(colorDefs color=bgColor,bool selected=false,status stat=enabledStatus,bool edit=false) const + { + return memByte(&(stat==enabledStatus?colors[color].enabled[selected+edit]:colors[color].disabled[selected])); + } + + void setBgColor(colorDefs c,bool selected=false,status s=enabledStatus,bool edit=false) + { + m_bgColor = getColor(c,selected,s,edit); + } + + void setColor(colorDefs c,bool selected=false,status s=enabledStatus,bool edit=false) override + { + currentColor = getColor(c,selected,s,edit); + } + + void clearLine(idx_t ln,idx_t panelNr=0,colorDefs color=bgColor,bool selected=false,status stat=enabledStatus,bool edit=false) override + { + const panel p=panels[panelNr]; + setBgColor(color,selected,stat,edit); + drawBox(p.x*resX + offsetX, (p.y+ln)*resY + offsetY, maxX()*resX, resY); + } + + void clear() override + { + sendCommand("CLR(7);"); + panels.reset(); + } + + void clear(idx_t panelNr) override + { + const panel p=panels[panelNr]; + setBgColor(bgColor,false,enabledStatus,false);; + drawBox(p.x*resX + offsetX,p.y*resY + offsetY,p.w*resX,p.h*resY); + panels.nodes[panelNr]=NULL; + } + + void box(idx_t panelNr,idx_t x,idx_t y,idx_t w=1,idx_t h=1,colorDefs c=bgColor,bool selected=false,status stat=enabledStatus,bool edit=false) override + { + const panel p=panels[panelNr]; + setBgColor(c, selected, stat, edit); + drawFrame((p.x+x)*resX,(p.y+y)*resY, w*resX, h*resY); + } + + void rect(idx_t panelNr,idx_t x,idx_t y,idx_t w=1,idx_t h=1,colorDefs c=bgColor,bool selected=false,status stat=enabledStatus,bool edit=false) override + { + const panel p=panels[panelNr]; + setBgColor(c, selected, stat, edit); + drawBox((p.x+x)*resX, (p.y+y)*resY, w*resX, h*resY); + } + + void setCursor(idx_t x,idx_t y,idx_t panelNr=0) override + { + const panel p=panels[panelNr]; + cursorX = (p.x+x)*resX+fontMarginX + offsetX; + cursorY = (p.y+y+1)*resY-fontMarginY + offsetY; + } + + void drawCursor(idx_t ln,bool selected,status stat,bool edit=false,idx_t panelNr=0) override + { + const panel p=panels[panelNr]; + setBgColor(cursorColor,selected,stat); + drawFrame(p.x*resX + offsetX, (p.y+ln)*resY + offsetY, maxX()*resX, resY); + } + + idx_t printRaw(const char* at,idx_t len) override + { + sprintf_P(buf,PSTR("SBC(%d);DCV%d(%d,%d,'%S',%d);"), m_bgColor, m_Font, cursorX, cursorY - resY + fontMarginY, at, currentColor); + sendCommand(buf); + cursorX = cursorX + strlen_P(at)*resX; + return strlen_P(at); + } + + private: + + void checkStreamReady() + { + int cnt = 0, timeOutCounter = 1000; + while (timeOutCounter-- > 0) + { + delay(1); + if (stream.available() > 0) + { + stream.read(); + if (++cnt == 4) break; + } + } + } + + void sendCommand(char * cmd) + { + stream.println(cmd); + //Serial.println(cmd); + checkStreamReady(); + } + + void drawFrame(int x, int y, int w, int h) + { + sprintf(buf, "BOX(%d,%d,%d,%d,%d);", x, y, x + w, y + h, m_bgColor); + sendCommand(buf); + } + + void drawBox(int x, int y, int w, int h) + { + sprintf(buf, "BOXF(%d,%d,%d,%d,%d);", x, y, x + w, y + h, m_bgColor); + sendCommand(buf); + } + }; +} +#endif //RSITE_ARDUINOP_MENU_UART From 7011eddfce35946738afd8973fa2806c030214f8 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 12 Oct 2018 14:32:01 +0300 Subject: [PATCH 008/197] Simple example for UART display --- examples/UART/uart_menu/uart_menu.ino | 97 +++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 examples/UART/uart_menu/uart_menu.ino diff --git a/examples/UART/uart_menu/uart_menu.ino b/examples/UART/uart_menu/uart_menu.ino new file mode 100644 index 00000000..4bec2d1e --- /dev/null +++ b/examples/UART/uart_menu/uart_menu.ino @@ -0,0 +1,97 @@ +/******************** +Arduino generic menu system + +Rui Azevedo - ruihfazevedo(@rrob@)gmail.com + +output: Serial +input: Serial +*/ + +#include + +#include +#include +#include +#include +#include +#include + +using namespace Menu; + +#define LEDPIN LED_BUILTIN + +SoftwareSerial ss(11, 10); + + +#define MAX_DEPTH 2 + +// define menu colors -------------------------------------------------------- +#define C_BLACK 0 +#define C_BLUE 3 +#define C_GRAY 7 +#define C_WHITE 15 +#define C_YELLOW 31 +#define C_RED 1 +#define C_GREEN 2 +//each color is in the format: +// {{disabled normal,disabled selected},{enabled normal,enabled selected, enabled editing}} +const colorDef colors[] MEMMODE={ + {{C_BLACK,C_BLACK}, {C_BLACK,C_BLUE,C_BLUE}},//bgColor + {{C_GRAY,C_GRAY}, {C_WHITE,C_WHITE,C_WHITE}},//fgColor + {{C_WHITE,C_BLACK}, {C_YELLOW,C_YELLOW,C_RED}},//valColor + {{C_WHITE,C_BLACK}, {C_WHITE,C_YELLOW,C_YELLOW}},//unitColor + {{C_WHITE,C_GRAY}, {C_BLACK,C_BLUE,C_WHITE}},//cursorColor + {{C_WHITE,C_YELLOW},{C_GREEN,C_WHITE,C_WHITE}},//titleColor +}; + + +#define offsetX 0 +#define offsetY 0 +#define U8_Width 240 +#define U8_Height 320 + +#define LEDPIN LED_BUILTIN + + +int timeOn=10; +int timeOff=90; + +MENU(mainMenu, "Settings menu", Menu::doNothing, Menu::noEvent, Menu::wrapStyle + ,FIELD(timeOn,"On","ms",0,100,10,1, Menu::doNothing, Menu::noEvent, Menu::noStyle) + ,FIELD(timeOff,"Off","ms",0,100,10,1,Menu::doNothing, Menu::noEvent, Menu::noStyle) + ,EXIT(" Date: Thu, 18 Oct 2018 19:46:08 +0000 Subject: [PATCH 009/197] text field edit h-scroll --- .../LCDs/LiquidCrystal/include/readme.txt | 39 +++++++++++++++++++ .../LCDs/Malpartida/I2C/include/readme.txt | 39 +++++++++++++++++++ examples/LCDs/PCF8574/include/readme.txt | 39 +++++++++++++++++++ examples/Serial/serialio/include/readme.txt | 39 +++++++++++++++++++ examples/Serial/serialio/platformio.ini | 2 +- .../Serial/serialio/serialio/serialio.ino | 5 +++ examples/lolin32/include/readme.txt | 39 +++++++++++++++++++ library.properties | 2 +- src/items.cpp | 5 ++- src/menuIo.cpp | 2 +- src/sync | 0 11 files changed, 206 insertions(+), 5 deletions(-) create mode 100644 examples/LCDs/LiquidCrystal/include/readme.txt create mode 100644 examples/LCDs/Malpartida/I2C/include/readme.txt create mode 100644 examples/LCDs/PCF8574/include/readme.txt create mode 100644 examples/Serial/serialio/include/readme.txt create mode 100644 examples/lolin32/include/readme.txt delete mode 100644 src/sync diff --git a/examples/LCDs/LiquidCrystal/include/readme.txt b/examples/LCDs/LiquidCrystal/include/readme.txt new file mode 100644 index 00000000..194dcd43 --- /dev/null +++ b/examples/LCDs/LiquidCrystal/include/readme.txt @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/examples/LCDs/Malpartida/I2C/include/readme.txt b/examples/LCDs/Malpartida/I2C/include/readme.txt new file mode 100644 index 00000000..194dcd43 --- /dev/null +++ b/examples/LCDs/Malpartida/I2C/include/readme.txt @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/examples/LCDs/PCF8574/include/readme.txt b/examples/LCDs/PCF8574/include/readme.txt new file mode 100644 index 00000000..194dcd43 --- /dev/null +++ b/examples/LCDs/PCF8574/include/readme.txt @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/examples/Serial/serialio/include/readme.txt b/examples/Serial/serialio/include/readme.txt new file mode 100644 index 00000000..194dcd43 --- /dev/null +++ b/examples/Serial/serialio/include/readme.txt @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/examples/Serial/serialio/platformio.ini b/examples/Serial/serialio/platformio.ini index e613ed09..b846d8c6 100644 --- a/examples/Serial/serialio/platformio.ini +++ b/examples/Serial/serialio/platformio.ini @@ -41,7 +41,7 @@ board = nanoatmega328 framework = arduino upload_port=/dev/ttyUSB* upload_flags=-V -build_flags = -DNODEBUG -Wno-strict-aliasing -Wno-sign-compare -Wno-write-strings +build_flags = -DNO_MENU_DEBUG -Wno-strict-aliasing -Wno-sign-compare -Wno-write-strings ; ; [env:teensy31] ; platform = teensy diff --git a/examples/Serial/serialio/serialio/serialio.ino b/examples/Serial/serialio/serialio/serialio.ino index 87a8a1c9..228f0c37 100644 --- a/examples/Serial/serialio/serialio/serialio.ino +++ b/examples/Serial/serialio/serialio/serialio.ino @@ -105,6 +105,10 @@ char* constMEM hexDigit MEMMODE="0123456789ABCDEF"; char* constMEM hexNr[] MEMMODE={"0","x",hexDigit,hexDigit}; char buf1[]="0x11"; +char* constMEM alphaNum MEMMODE=" 0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz,\\|!\"#$%&/()=?~*^+-{}[]€"; +char* constMEM alphaNumMask[] MEMMODE={alphaNum}; +char name[]=" "; + MENU(mainMenu,"Main menu",zZz,noEvent,wrapStyle ,OP("Op1",action1,anyEvent) ,OP("Op2",action2,enterEvent) @@ -116,6 +120,7 @@ MENU(mainMenu,"Main menu",zZz,noEvent,wrapStyle ,SUBMENU(selMenu) ,SUBMENU(chooseMenu) ,OP("Alert test",doAlert,enterEvent) + ,EDIT("Name",name,alphaNumMask,doNothing,noEvent,noStyle) ,EDIT("Hex",buf1,hexNr,doNothing,noEvent,noStyle) ,SUBMENU(birthDate) ,EXIT("=w?cursor-w:0; + trace(MENU_DEBUG_OUT<<"at:"< Date: Fri, 2 Nov 2018 05:08:39 -0700 Subject: [PATCH 010/197] Add files via upload --- .../tft_interrupt/tft_interrupt.ino | 295 ++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 examples/adafruitGfx/tft_interrupt/tft_interrupt.ino diff --git a/examples/adafruitGfx/tft_interrupt/tft_interrupt.ino b/examples/adafruitGfx/tft_interrupt/tft_interrupt.ino new file mode 100644 index 00000000..3bfc881c --- /dev/null +++ b/examples/adafruitGfx/tft_interrupt/tft_interrupt.ino @@ -0,0 +1,295 @@ +#include + +/******************** +Sept. 2014 ~ Oct 2016 Rui Azevedo - ruihfazevedo(@rrob@)gmail.com +Oct. 2018 - modified by Kevin O'rourke to use interrupts on pins for the sam3x + +menu with the newer adafruit GFX +output: 1.8" TFT 128*160 (ST7735 HW SPI) or +output: 1.8" TFT 128*160 (ST7735 SOFT SPI) + +input: Serial + interrupts +www.r-site.net + +***/ + +//removed as extra libs are not included into travis +// #define USE_CLICK_ENCODER +#define USE_INTERRUPT_PINS // using a joy button +#define DONT_SHOW_SUSPEND // dont show the suspended screen + +#include +#include +#include +#include +#include +#ifndef USE_INTERRUPT_PINS + #ifdef USE_CLICK_ENCODER + #include + #include + #include + #else + #include + #endif + #include + #include + #include + #include +#else + #include + #include + #include + #include + +#endif + + +using namespace Menu; + +//ST7735 1.8TFT 128x160 +//#define TFT_CS A1 +//#define TFT_DC A0 +//#define TFT_RST A2 + + + +void wait_for(uint32_t wait) { + uint64_t myMillis = wait * 11986; // approx 11986000 nop nop per sec + for (uint64_t Counting = 0; Counting <= myMillis; Counting++) { + __asm__("nop\n\t"); + } +} + + +#define SPI_SCK 13 +#define SPI_DI 12 +#define SPI_DO 11 +#define TFT_CS 15 +#define TFT_RST 0 +#define TFT_DC 8 + +//Adafruit_ST7735 gfx(TFT_CS, TFT_DC, TFT_RST); // hardware if possible + +Adafruit_ST7735 gfx = Adafruit_ST7735(TFT_CS, TFT_DC, SPI_DO, SPI_SCK, TFT_RST);// software spi on the due + +#define LEDPIN LED_BUILTIN + +#ifndef USE_INTERRUPT_PINS + // rotary encoder pins + #define encA 2 + #define encB 3 + #define encBtn 4 +#else + // interrupt pins sam3x with joy button + #define BTN_UP 2 + #define BTN_DOWN 3 + #define BTN_SEL 5 + #define BTN_LEFT 6 + #define BTN_RIGHT 7 +#endif + +result doAlert(eventMask e, prompt &item); + +int test=55; + +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 confirmExit:public menu { +public: + confirmExit(constMEM menuNodeShadow& shadow):menu(shadow) {} + Used printTo(navRoot &root,bool sel,menuOut& out, idx_t idx,idx_t len,idx_t p) override { + if(idx<0){menu::printTo(root,sel,out,idx,len,p);} + else{out.printRaw((constText*)F("Exit"),len);} + return idx; + } +}; +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);; + } +}; + +result systemExit(); +altMENU(confirmExit,subMenu2,"Exit?",doNothing,noEvent,wrapStyle,(Menu::_menuData|Menu::_canNav) + ,OP("Yes",systemExit,enterEvent) + ,EXIT("Cancel") +); + +MENU(subMenu,"Sub-Menu",doNothing,noEvent,noStyle + ,altOP(altPrompt,"",doNothing,noEvent) + ,OP("Op",doNothing,noEvent) + ,EXIT(" colors[] MEMMODE={ + {{ST7735_BLACK,ST7735_BLACK},{ST7735_BLACK,ST7735_BLUE,ST7735_BLUE}},//bgColor + {{ST7735_GRAY,ST7735_GRAY},{ST7735_WHITE,ST7735_WHITE,ST7735_WHITE}},//fgColor + {{ST7735_WHITE,ST7735_BLACK},{ST7735_YELLOW,ST7735_YELLOW,ST7735_RED}},//valColor + {{ST7735_WHITE,ST7735_BLACK},{ST7735_WHITE,ST7735_YELLOW,ST7735_YELLOW}},//unitColor + {{ST7735_WHITE,ST7735_GRAY},{ST7735_BLACK,ST7735_BLUE,ST7735_WHITE}},//cursorColor + {{ST7735_WHITE,ST7735_YELLOW},{ST7735_BLUE,ST7735_RED,ST7735_RED}},//titleColor +}; + +serialIn serial(Serial); + +#ifndef USE_INTERRUPT_PINS + #ifdef USE_CLICK_ENCODER + ClickEncoder clickEncoder(encA,encB,encBtn); + ClickEncoderStream encStream(clickEncoder,1); + MENU_INPUTS(in,&encStream,&serial); + void timerIsr() {clickEncoder.service();} + #else + encoderIn encoder;//simple quad encoder driver + encoderInStream 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 + MENU_INPUTS(in,&encStream,&encButton,&serial); + #endif +#else + encoderIn encoder;//simple quad encoder driver + encoderInStream encStream(encoder);// simple quad encoder fake Stream + MENU_INPUTS(in,&encStream,&serial); +#endif + +#define MAX_DEPTH 4 +#define textScale 1 +MENU_OUTPUTS(out,MAX_DEPTH + ,ADAGFX_OUT(gfx,colors,6*textScale,9*textScale,{0,0,14,8},{14,0,14,8}) + ,SERIAL_OUT(Serial) +); + +NAVROOT(nav,mainMenu,MAX_DEPTH,in,out); + +//when menu is suspended +result idle(menuOut& o,idleEvent e) { +#ifndef DONT_SHOW_SUSPEND + if (e==idling) { + o.println(F("suspended...")); + o.println(F("press [select]")); + o.println(F("to continue")); + } +#endif + return proceed; +} + +result systemExit() { + encoder.menu_running = false;//prevents the menu from running again! + nav.reset(); + nav.idleOn();//suspend the menu system + gfx.fillScreen(ST7735_BLACK); + return quit; +} +//config myOptions('*','-',defaultNavCodes,false); + +void setup() { + //options=&myOptions;//can customize options + pinMode(LEDPIN,OUTPUT); + Serial.begin(211000); + while(!Serial); + Serial.println("menu 4.x test"); + Serial.flush(); + + //outGfx.usePreview=true;//reserve one panel for preview? + //nav.showTitle=false;//show menu title? + + //pinMode(encBtn, INPUT_PULLUP); +#ifndef USE_INTERRUPT_PINS + #ifdef USE_CLICK_ENCODER + Timer1.initialize(1000); + Timer1.attachInterrupt(timerIsr); + #else + encButton.begin(); + encoder.begin(); + #endif + nav.idleTask=idle;//point a function to be used when menu is suspended +#else + encoder.begin(); + nav.idleOn(); // suspend the menu system +#endif + mainMenu[0].disable(); + SPI.begin(); + gfx.initR(INITR_BLACKTAB); + gfx.setRotation(3); + gfx.setTextSize(textScale);//test scalling + gfx.setTextWrap(false); + gfx.fillScreen(ST7735_BLACK); + gfx.setTextColor(ST7735_RED,ST7735_BLACK); + gfx.println("Menu 4.x test on GFX"); + delay(2000); + gfx.fillScreen(ST7735_BLACK); +} + +void loop() { + +#ifndef USE_INTERRUPT_PINS + nav.poll();//this device only draws when needed + delay(100);//simulate a delay when other tasks are done +#else + if((encoder.menu_running)&&(encoder.menu_interrupt)){ + encoder.menu_interrupt = false; + nav.doInput(); + nav.doOutput(); + } +#endif + digitalWrite(LEDPIN, ledCtrl); +} From e36d3bba6dcc26d948fabc88e78f984661bb86d0 Mon Sep 17 00:00:00 2001 From: knockoutperformance Date: Fri, 2 Nov 2018 05:12:24 -0700 Subject: [PATCH 011/197] Add files via upload interrupt based input for joy button om Arduino due --- src/menuIO/interruptPins.h | 169 +++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 src/menuIO/interruptPins.h diff --git a/src/menuIO/interruptPins.h b/src/menuIO/interruptPins.h new file mode 100644 index 00000000..b1d21ce3 --- /dev/null +++ b/src/menuIO/interruptPins.h @@ -0,0 +1,169 @@ +/* -*- C++ -*- */ +/******************** +Sept. 2014 Rui Azevedo - ruihfazevedo(@rrob@)gmail.com +Oct. 2018 - modified for pin interrupts Kevin O'Rourke + +quadrature encoder driver (PCINT) +quadrature encoder stream (fake, not using buffers) + +*/ + +#ifndef RSITE_ARDUINO_MENU_ENCODER + #define RSITE_ARDUINO_MENU_ENCODER + + //#include //https://github.com/neu-rah/PCINT + #include "../menuDefs.h" + + namespace Menu { + + template + class encoderIn { + public: + volatile int pos = 0; + volatile bool menu_running = false; + volatile bool menu_interrupt = false; + volatile unsigned long last_interrupt_time = 0; + void begin() { + pinMode(pinUP, INPUT_PULLUP); + pinMode(pinDOWN, INPUT_PULLUP); + pinMode(pinSEL, INPUT_PULLUP); + pinMode(pinLEFT, INPUT_PULLUP); + pinMode(pinRIGHT, INPUT_PULLUP); + PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateA,this), LOW); + PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateB,this), LOW); + PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateC,this), LOW); + PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateD,this), LOW); + PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateE,this), LOW); + } + static void encoderInUpdateA(class encoderIn *e); + static void encoderInUpdateB(class encoderIn *e); + static void encoderInUpdateC(class encoderIn *e); + static void encoderInUpdateD(class encoderIn *e); + static void encoderInUpdateE(class encoderIn *e); + }; + + //PCint handlers + + template + void encoderIn::encoderInUpdateA(class encoderIn *e) { + unsigned long interrupt_time = millis(); + if (interrupt_time - e->last_interrupt_time > 20UL){ + if(e->menu_running){ + e->menu_interrupt = true; + e->pos++; + } + } + e->last_interrupt_time = interrupt_time; + } + + template + void encoderIn::encoderInUpdateB(class encoderIn *e) { + unsigned long interrupt_time = millis(); + if (interrupt_time - e->last_interrupt_time > 20UL){ + if(e->menu_running){ + e->menu_interrupt = true; + e->pos--; + } + } + e->last_interrupt_time = interrupt_time; + } + + template + void encoderIn::encoderInUpdateC(class encoderIn *e) { + unsigned long interrupt_time = millis(); + if (interrupt_time - e->last_interrupt_time > 20UL){ + if(e->menu_running){ + e->pos+=2; + }else if(!e->menu_running) { + e->menu_running = true;//lock menu if false + } + e->menu_interrupt = true; + } + e->last_interrupt_time = interrupt_time; + } + + template + void encoderIn::encoderInUpdateD(class encoderIn *e) { + unsigned long interrupt_time = millis(); + if (interrupt_time - e->last_interrupt_time > 20UL){ + if(e->menu_running){ + e->menu_interrupt = true; + e->pos+=3; + } + } + e->last_interrupt_time = interrupt_time; + } + + template + void encoderIn::encoderInUpdateE(class encoderIn *e) { + unsigned long interrupt_time = millis(); + if (interrupt_time - e->last_interrupt_time > 20UL){ + if(e->menu_running){ + e->menu_interrupt = true; + e->pos-=3; + } + } + e->last_interrupt_time = interrupt_time; + } + + //emulate a stream based on encoderIn movement returning +/- for every step + //buffer not needer because we have an accumulator + template + class encoderInStream:public menuIn { + public: + encoderIn &enc;//associated hardware encoderIn + encoderInStream(encoderIn &enc):enc(enc) {} + int oldPos = 0; + int available(void) {return abs(enc.pos-oldPos);} + int peek(void) override { + int d = enc.pos-oldPos; + if (d==-1)return options->navCodes[downCmd].ch; + if (d==1) return options->navCodes[upCmd].ch; + if (d>=2) { + if (d>=3){ + return options->navCodes[leftCmd].ch; + }else{ + return options->navCodes[enterCmd].ch; + } + } + if (d<=-3){ + return options->navCodes[rightCmd].ch; + } + return -1; + } + int read() override { + int d=enc.pos-oldPos; + if (d==-1) { + oldPos-=1; + return options->navCodes[downCmd].ch; + } + if (d==1) { + oldPos+=1; + return options->navCodes[upCmd].ch; + } + if (d>=2) { + if (d>=3){ + oldPos+=3; + return options->navCodes[leftCmd].ch; + }else{ + oldPos+=2; + return options->navCodes[enterCmd].ch; + } + } + if (d<=-3){ + oldPos-=3; + return options->navCodes[rightCmd].ch; + } + return -1; + } + void flush() { + oldPos = enc.pos; + } + size_t write(uint8_t v) { + oldPos = v; + return 1; + } + }; + }//namespace Menu +#endif +//void doNav(navCmd cmd);//fly by wire mode \ No newline at end of file From e6c2cde241c799b1183808fdb794d03d6b036d37 Mon Sep 17 00:00:00 2001 From: knockoutperformance Date: Fri, 2 Nov 2018 05:13:14 -0700 Subject: [PATCH 012/197] Update interruptPins.h --- src/menuIO/interruptPins.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/menuIO/interruptPins.h b/src/menuIO/interruptPins.h index b1d21ce3..a2d8ff06 100644 --- a/src/menuIO/interruptPins.h +++ b/src/menuIO/interruptPins.h @@ -11,7 +11,7 @@ quadrature encoder stream (fake, not using buffers) #ifndef RSITE_ARDUINO_MENU_ENCODER #define RSITE_ARDUINO_MENU_ENCODER - //#include //https://github.com/neu-rah/PCINT + #include //https://github.com/neu-rah/PCINT #include "../menuDefs.h" namespace Menu { @@ -166,4 +166,4 @@ quadrature encoder stream (fake, not using buffers) }; }//namespace Menu #endif -//void doNav(navCmd cmd);//fly by wire mode \ No newline at end of file +//void doNav(navCmd cmd);//fly by wire mode From 69b64304dfff4bacd7b2e793b24d7f4e5661f4dc Mon Sep 17 00:00:00 2001 From: knockoutperformance Date: Fri, 2 Nov 2018 05:16:42 -0700 Subject: [PATCH 013/197] Update interruptPins.h --- src/menuIO/interruptPins.h | 62 +++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/menuIO/interruptPins.h b/src/menuIO/interruptPins.h index a2d8ff06..baa16baf 100644 --- a/src/menuIO/interruptPins.h +++ b/src/menuIO/interruptPins.h @@ -20,24 +20,24 @@ quadrature encoder stream (fake, not using buffers) class encoderIn { public: volatile int pos = 0; - volatile bool menu_running = false; - volatile bool menu_interrupt = false; - volatile unsigned long last_interrupt_time = 0; + volatile bool menu_running = false; + volatile bool menu_interrupt = false; + volatile unsigned long last_interrupt_time = 0; void begin() { pinMode(pinUP, INPUT_PULLUP); pinMode(pinDOWN, INPUT_PULLUP); - pinMode(pinSEL, INPUT_PULLUP); + pinMode(pinSEL, INPUT_PULLUP); pinMode(pinLEFT, INPUT_PULLUP); pinMode(pinRIGHT, INPUT_PULLUP); PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateA,this), LOW); PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateB,this), LOW); PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateC,this), LOW); - PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateD,this), LOW); - PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateE,this), LOW); + PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateD,this), LOW); + PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateE,this), LOW); } static void encoderInUpdateA(class encoderIn *e); static void encoderInUpdateB(class encoderIn *e); - static void encoderInUpdateC(class encoderIn *e); + static void encoderInUpdateC(class encoderIn *e); static void encoderInUpdateD(class encoderIn *e); static void encoderInUpdateE(class encoderIn *e); }; @@ -113,24 +113,24 @@ quadrature encoder stream (fake, not using buffers) public: encoderIn &enc;//associated hardware encoderIn encoderInStream(encoderIn &enc):enc(enc) {} - int oldPos = 0; + int oldPos = 0; int available(void) {return abs(enc.pos-oldPos);} int peek(void) override { int d = enc.pos-oldPos; if (d==-1)return options->navCodes[downCmd].ch; if (d==1) return options->navCodes[upCmd].ch; - if (d>=2) { - if (d>=3){ - return options->navCodes[leftCmd].ch; - }else{ - return options->navCodes[enterCmd].ch; - } + if (d>=2) { + if (d>=3){ + return options->navCodes[leftCmd].ch; + }else{ + return options->navCodes[enterCmd].ch; + } } - if (d<=-3){ - return options->navCodes[rightCmd].ch; - } + if (d<=-3){ + return options->navCodes[rightCmd].ch; + } return -1; - } + } int read() override { int d=enc.pos-oldPos; if (d==-1) { @@ -141,21 +141,21 @@ quadrature encoder stream (fake, not using buffers) oldPos+=1; return options->navCodes[upCmd].ch; } - if (d>=2) { - if (d>=3){ - oldPos+=3; - return options->navCodes[leftCmd].ch; - }else{ - oldPos+=2; - return options->navCodes[enterCmd].ch; - } - } - if (d<=-3){ - oldPos-=3; - return options->navCodes[rightCmd].ch; + if (d>=2) { + if (d>=3){ + oldPos+=3; + return options->navCodes[leftCmd].ch; + }else{ + oldPos+=2; + return options->navCodes[enterCmd].ch; } - return -1; + } + if (d<=-3){ + oldPos-=3; + return options->navCodes[rightCmd].ch; } + return -1; + } void flush() { oldPos = enc.pos; } From 9a4dcb25ff23eb267f3a406daac873d8fdc195b2 Mon Sep 17 00:00:00 2001 From: knockoutperformance Date: Fri, 2 Nov 2018 05:18:38 -0700 Subject: [PATCH 014/197] Update interruptPins.h --- src/menuIO/interruptPins.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/menuIO/interruptPins.h b/src/menuIO/interruptPins.h index baa16baf..85751f00 100644 --- a/src/menuIO/interruptPins.h +++ b/src/menuIO/interruptPins.h @@ -24,14 +24,14 @@ quadrature encoder stream (fake, not using buffers) volatile bool menu_interrupt = false; volatile unsigned long last_interrupt_time = 0; void begin() { - pinMode(pinUP, INPUT_PULLUP); - pinMode(pinDOWN, INPUT_PULLUP); + pinMode(pinUP, INPUT_PULLUP); + pinMode(pinDOWN, INPUT_PULLUP); pinMode(pinSEL, INPUT_PULLUP); - pinMode(pinLEFT, INPUT_PULLUP); - pinMode(pinRIGHT, INPUT_PULLUP); - PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateA,this), LOW); - PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateB,this), LOW); - PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateC,this), LOW); + pinMode(pinLEFT, INPUT_PULLUP); + pinMode(pinRIGHT, INPUT_PULLUP); + PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateA,this), LOW); + PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateB,this), LOW); + PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateC,this), LOW); PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateD,this), LOW); PCattachInterrupt(mixHandler((void(*)(void*))encoderInUpdateE,this), LOW); } From 8a346e24f3e2882cf4095f807448d6f587649a10 Mon Sep 17 00:00:00 2001 From: Rui Azevedo Date: Fri, 2 Nov 2018 11:48:04 -0100 Subject: [PATCH 015/197] debug stuff --- src/nav.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nav.cpp b/src/nav.cpp index ea2567d0..900cf80f 100644 --- a/src/nav.cpp +++ b/src/nav.cpp @@ -192,6 +192,7 @@ navCmd navRoot::enter() { bool isMenu=sel.isMenu(); result go=node().event(enterEvent);//item event sent here navCmd rCmd=enterCmd; + trace(Serial<<"go:"<dirty=true; if (!isMenu) in.fieldOn(); From 662ca642b15a504391b360f7378f64521324391e Mon Sep 17 00:00:00 2001 From: Aleksei Prokopov Date: Tue, 13 Nov 2018 19:21:59 +0200 Subject: [PATCH 016/197] add pin setup to keyMapDef --- src/menuIO/keyMapDef.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/menuIO/keyMapDef.h b/src/menuIO/keyMapDef.h index 10a9035a..737c9a51 100644 --- a/src/menuIO/keyMapDef.h +++ b/src/menuIO/keyMapDef.h @@ -6,6 +6,7 @@ struct keyMap { int8_t pin; int8_t code; + uint8_t mode; }; #endif From 083c3ab2e56f85df74da9f90f09aa081dcfba0d9 Mon Sep 17 00:00:00 2001 From: Aleksei Prokopov Date: Tue, 13 Nov 2018 19:50:14 +0200 Subject: [PATCH 017/197] Use third parameter mode --- src/menuIO/keyIn.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/menuIO/keyIn.h b/src/menuIO/keyIn.h index c253e695..da8e688f 100644 --- a/src/menuIO/keyIn.h +++ b/src/menuIO/keyIn.h @@ -33,8 +33,8 @@ ex: -A0 means: pin A0 normally high, low when button pushed (reverse logic) keyIn(keyMap k[]):keys(k),lastkey(-1) {} void begin() { for(int n=0;n Date: Mon, 31 Dec 2018 18:18:22 -0100 Subject: [PATCH 018/197] formating json have to put some order in separators --- library.properties | 2 +- src/itemsTemplates.cpp | 4 +- src/menu.cpp | 2 +- src/menuIO/esp8266Out.h | 1 + src/menuIO/jsonFmt.cpp | 30 ++++++++++- src/menuIO/jsonFmt.h | 107 ++++++++++++++++++++++++++-------------- src/menuIO/xmlFmt.h | 2 + src/menuIo.cpp | 13 +++-- src/menuIo.h | 2 +- test.json | 27 ++++++++++ 10 files changed, 144 insertions(+), 46 deletions(-) create mode 100644 test.json diff --git a/library.properties b/library.properties index 2d711b31..d65d988e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ArduinoMenu library -version=4.14.1 +version=4.15.0 author=Rui Azevedo, ruihfazevedo@gmail.com maintainer=neu-rah, ruihfazevedo@gmail.com sentence=Generic menu/interactivity system diff --git a/src/itemsTemplates.cpp b/src/itemsTemplates.cpp index ba828bb4..3180cfe4 100644 --- a/src/itemsTemplates.cpp +++ b/src/itemsTemplates.cpp @@ -146,7 +146,7 @@ namespace Menu { for(idx_t i=0;i*)&operator[](i))->target()==target()) return i; #ifdef MENU_DEBUG - MENU_DEBUG_OUT.print(F("value out of range ")); + MENU_DEBUG_OUT.print("value out of range "); MENU_DEBUG_OUT.println(target());MENU_DEBUG_OUT.flush(); assert(false); #endif @@ -157,7 +157,7 @@ namespace Menu { #ifdef MENU_DEBUG if (!(i>=0&&i=0&&i //#include #include + #include "xmlFmt.h" using namespace std; diff --git a/src/menuIO/jsonFmt.cpp b/src/menuIO/jsonFmt.cpp index 5a23e5f3..b1f11294 100644 --- a/src/menuIO/jsonFmt.cpp +++ b/src/menuIO/jsonFmt.cpp @@ -3,8 +3,36 @@ #include "jsonFmt.h" namespace Menu { + #ifdef MENU_DEBUG + int partIndent=0; + const char* partName(menuOut::fmtParts part) { + switch (part){ + case menuOut::fmtPanel: return "fmtPanel"; + case menuOut::fmtTitle: return "fmtTitle"; + case menuOut::fmtBody: return "fmtBody"; + case menuOut::fmtOp: return "fmtOp"; + case menuOut::fmtIdx: return "fmtIdx"; + case menuOut::fmtCursor: return "fmtCursor"; + case menuOut::fmtOpBody: return "fmtOpBody"; + case menuOut::fmtPreview: return "fmtPreview"; + case menuOut::fmtPrompt: return "fmtPrompt"; + case menuOut::fmtField: return "fmtField"; + case menuOut::fmtToggle: return "fmtToggle"; + case menuOut::fmtSelect: return "fmtSelect"; + case menuOut::fmtChoose: return "fmtChoose"; + case menuOut::fmtUnit: return "fmtUnit"; + case menuOut::fmtTextField: return "fmtTextField"; + default: return "???"; + } + } + void printIndent() { + for(int n=0;n0) *this<<",\n"; + else "\n"; + *this<<"{\"idx\":\""<"<"; break; case menuOut::fmtCursor: + case menuOut::fmtCursorOpen: + case menuOut::fmtCursorClose: if (start) *this<<""; break; diff --git a/src/menuIo.cpp b/src/menuIo.cpp index de986e7e..eee512b6 100644 --- a/src/menuIo.cpp +++ b/src/menuIo.cpp @@ -401,13 +401,15 @@ Used menuOut::printMenu(navNode &nav,idx_t panelNr) { #endif //------> cursorStart #ifdef MENU_FMT_WRAPS - fmtStart(p,fmtCursor,nav,i); + fmtStart(p,fmtCursorOpen,nav,i); + // fmtStart(p,fmtCursor,nav,i); #endif if (asPad&&selected) print("["); else drawCursor(ist,selected,p.enabled,ed,panelNr);//assuming only one character //<------ cursorEnd #ifdef MENU_FMT_WRAPS - fmtEnd(p,fmtCursor,nav,i); + fmtEnd(p,fmtCursorOpen,nav,i); + // fmtEnd(p,fmtCursor,nav,i); #endif len--; //---->opBodyStart @@ -419,11 +421,13 @@ Used menuOut::printMenu(navNode &nav,idx_t panelNr) { if (len>0) { if (asPad) { #ifdef MENU_FMT_WRAPS - fmtStart(p,fmtCursor,nav,i); + // fmtStart(p,fmtCursor,nav,i); + fmtStart(p,fmtCursorClose,nav,i); #endif print(selected?"]":""); #ifdef MENU_FMT_WRAPS - fmtEnd(p,fmtCursor,nav,i); + fmtEnd(p,fmtCursorClose,nav,i); + // fmtEnd(p,fmtCursor,nav,i); #endif len--; } @@ -457,6 +461,7 @@ Used menuOut::printMenu(navNode &nav,idx_t panelNr) { #ifdef MENU_FMT_WRAPS fmtEnd(*nav.target,fmtPanel,nav,-1); #endif + trace(MENU_DEBUG_OUT<<"ENDING menuOut::printMenu(navNode &nav,idx_t panelNr)"<","prompt":"", + "pad":[ + {"idx":"0","enabled":"1","cursor":" ","prompt":"" ,"field":"1","range":{"low":"1","high":"31","step":"1","tune":"0"},"unit":"/"}, + {"idx":"1","enabled":"1","cursor":" ","prompt":"" ,"field":"1","range":{"low":"1","high":"12","step":"1","tune":"0"},"unit":"/"}, + {"idx":"2","enabled":"1","cursor":" ","prompt":"" ,"field":"2000","range":{"low":"2000","high":"2100","step":"10","tune":"1"},"unit":""} + ] + }, + {"idx":"1","enabled":"1","cursor":" ","prompt":"", + "pad":[ + {"idx":"0","enabled":"1","cursor":" ","prompt":"" ,"field":"0","range":{"low":"0","high":"23","step":"1","tune":"0"},"unit":":"}, + {"idx":"1","enabled":"1","cursor":" ","prompt":"" ,"field":"6","range":{"low":"0","high":"59","step":"10","tune":"1"},"unit":":"}, + {"idx":"2","enabled":"1","cursor":" ","prompt":"" ,"field":"33","range":{"low":"0","high":"59","step":"10","tune":"1"},"unit":""} + ] + }, + {"idx":"2","enabled":"1","cursor":" ","prompt":"GMT" ,"field":"-1","range":{"low":"-11","high":"12","step":"1","tune":"0"},"unit":""}, + {"idx":"3","enabled":"1","cursor":" ","prompt":"Sommerzeit:""tog":["options":[2]],"value":An,}, + {"idx":"4","enabled":"1","cursor":" ","prompt":"benutze NTP"}, + {"idx":"5","enabled":"1","cursor":" ","prompt":"Speichern"}, + {"idx":"6","enabled":"1","cursor":" ","prompt":"Zurück"} + ] + } +} From 12eb5b0e7ecfce7745834105d84c19bec2fc7fce Mon Sep 17 00:00:00 2001 From: Rui Azevedo Date: Wed, 2 Jan 2019 03:23:55 -0100 Subject: [PATCH 019/197] implementing json format some fixes --- src/items.cpp | 6 +++++ src/menuIO/esp8266Out.h | 49 +++++++++++++++++++++++++++++-------- src/menuIO/jsonFmt.cpp | 5 +++- src/menuIO/jsonFmt.h | 54 +++++++++++++++++++++++++---------------- src/menuIO/xmlFmt.h | 4 +++ src/menuIo.h | 3 ++- test.json | 42 ++++++++++++++------------------ 7 files changed, 106 insertions(+), 57 deletions(-) diff --git a/src/items.cpp b/src/items.cpp index a9b5fdb7..bdc916d9 100644 --- a/src/items.cpp +++ b/src/items.cpp @@ -174,10 +174,16 @@ Used textField::printTo(navRoot &root,bool sel,menuOut& out, idx_t idx,idx_t len bool editing=this==root.navFocus; trace(MENU_DEBUG_OUT<<"editing:"< esp8266Out& operator<<(T t)=0; }; + class esp8266BufferedOut:public esp8266Out { + public: + String response; + using esp8266Out::esp8266Out; + template inline esp8266BufferedOut& operator<<(T t) {response< inline String& operator<<(String& o,T t) {return o.operator+=(t);} - class esp8266_WebServerOut:public esp8266Out { + class esp8266_WebServerOut:public esp8266BufferedOut { public: - String response; ESP8266WebServer &server; //using esp8266Out::esp8266Out; esp8266_WebServerOut( @@ -62,20 +69,42 @@ /*const colorDef (&c)[nColors],*/ idx_t* t, panelsList& p - ):esp8266Out(t,p),server(srv) {} + ):esp8266BufferedOut(t,p),server(srv) {} size_t write(uint8_t ch) override {response<<(char)ch;return 1;} - template inline esp8266_WebServerOut& operator<<(T t) {response< inline esp8266_WebServerOut& operator<<(T t) {response< inline esp8266_WebServerStreamOut& operator<<(T t) { + server.sendContent(String()+t); + return *this; + } }; + // class esp8266_WebSocketOut:public esp8266BufferedOut { + // public: + // //client num... well we only serve a client at a time, so its safe to put t here + // // of course this kind of code is not thead safe...but we dont have theads anyway + // uint8_t num; + // String response; + // WebSocketsServer &webSocket; + // esp8266_WebSocketOut(WebSocketsServer &socket,idx_t* tops,panelsList& panels) + // :webSocket(socket),esp8266BufferedOut(tops,panels,(menuOut::styles)(minimalRedraw|expandEnums)) {} + // size_t write(uint8_t ch) override {response<<(char)ch;return 1;} + // }; + //template inline esp8266_WebServerOut& operator<<(esp8266_WebServerOut&o , T t) {return o.operator<<(t);} //template inline esp8266_WiFiClientOut& operator<<(esp8266_WiFiClientOut&o , T t) {return o.operator<<(t);} //template inline esp8266Out& operator<<(esp8266Out&o , T t) {return o.operator<<(t);} diff --git a/src/menuIO/jsonFmt.cpp b/src/menuIO/jsonFmt.cpp index b1f11294..44633885 100644 --- a/src/menuIO/jsonFmt.cpp +++ b/src/menuIO/jsonFmt.cpp @@ -22,6 +22,9 @@ case menuOut::fmtChoose: return "fmtChoose"; case menuOut::fmtUnit: return "fmtUnit"; case menuOut::fmtTextField: return "fmtTextField"; + case menuOut::fmtCursorOpen: return "fmtCursorOpen"; + case menuOut::fmtCursorClose: return "fmtCursorClose"; + case menuOut::fmtValue: return "fmtVluea"; default: return "???"; } } @@ -31,7 +34,7 @@ #endif int cursorCtrl=0; void jsonOptions(menuOut& o,navNode &nav,menuNode& node,idx_t idx) { - o<<"\",options\":["; + o<<",\"options\":["; // o<0) *this<<",\n"; - else "\n"; - *this<<"{\"idx\":\""<=0) *this<<","; *this<<"\"prompt\":\""; } else { *this<<"\""; @@ -69,17 +70,25 @@ *this<<",\"pad\":["; }; break; + case menuOut::fmtValue: + if (start) *this<<",\"value\":\""; + else *this<<"\""; + break; case menuOut::fmtSelect: if (start) { - *this<<",\"type\":\"select\""; + *this<<",\"select\":\""; + } else { + *this<<"\""; jsonOptions(*this,nav,*(menuNode*)&target,idx); - } else *this<<""; + } break; case menuOut::fmtChoose: if (start) { - *this<<"\"choose\":"; + *this<<",\"choose\":\""; + } else { + *this<<"\""; jsonOptions(*this,nav,*(menuNode*)&target,idx); - } else *this<<","; + } break; break; case menuOut::fmtField: @@ -95,24 +104,27 @@ *this<<"\",\"tune\":\""; target.printTune(*this); *this<<"\"}"; - *this<<","; } break; + case menuOut::fmtEditCursor: + if (start) *this<<",\"editCursor\":\""; + else *this<<"\""; + break; case menuOut::fmtTextField: if (start) *this<<",\"text\":\""; - else *this<<"\"\n"; + else *this<<"\""; break; case menuOut::fmtIdx: // if (start) *this<<"\"idx\":"; // else *this<<","; break; case menuOut::fmtCursor: - if (start) *this<<"\"cursor\":\""; - else *this<<"\","; + if (start) *this<<",\"cursor\":\""; + else *this<<"\""; break; case menuOut::fmtCursorOpen: - if (start) *this<<"\"selStart\":\""; - else *this<<"\","; + if (start) *this<<",\"selStart\":\""; + else *this<<"\""; break; case menuOut::fmtCursorClose: if (start) *this<<",\"selEnd\":\""; @@ -128,8 +140,8 @@ } break; case menuOut::fmtPreview: - if (start) *this<<"\"preview\":"; - else *this<<",\n"; + if (start) *this<<",\"preview\":\""; + else *this<<"\"\n"; break; default:break; } diff --git a/src/menuIO/xmlFmt.h b/src/menuIO/xmlFmt.h index ff5606b0..09038a95 100644 --- a/src/menuIO/xmlFmt.h +++ b/src/menuIO/xmlFmt.h @@ -126,6 +126,10 @@ *this<<"\">"; break; + case menuOut::fmtEditCursor: + if (start) *this<<""; + break; case menuOut::fmtTextField: if (start) *this<<""; diff --git a/src/menuIo.h b/src/menuIo.h index 2fbd1f4a..40f0d33f 100644 --- a/src/menuIo.h +++ b/src/menuIo.h @@ -64,7 +64,8 @@ fmtPanel,fmtTitle,fmtBody,fmtOp, fmtIdx,fmtCursor,fmtOpBody,fmtPreview, fmtPrompt,fmtField,fmtToggle,fmtSelect, - fmtChoose,fmtUnit,fmtTextField,fmtCursorOpen,fmtCursorClose + fmtChoose,fmtUnit,fmtTextField,fmtCursorOpen, + fmtCursorClose,fmtValue,fmtEditCursor }; menuNode* drawn=NULL; bool pageScroll=false; diff --git a/test.json b/test.json index be710d0b..1a448f67 100644 --- a/test.json +++ b/test.json @@ -1,27 +1,21 @@ { "output":"", - "menu":{ - "title":{"prompt":"Zeit/Datum einstellen"}, - "sel":"0","items":[ - {"idx":"0","enabled":"1","cursor":">","prompt":"", - "pad":[ - {"idx":"0","enabled":"1","cursor":" ","prompt":"" ,"field":"1","range":{"low":"1","high":"31","step":"1","tune":"0"},"unit":"/"}, - {"idx":"1","enabled":"1","cursor":" ","prompt":"" ,"field":"1","range":{"low":"1","high":"12","step":"1","tune":"0"},"unit":"/"}, - {"idx":"2","enabled":"1","cursor":" ","prompt":"" ,"field":"2000","range":{"low":"2000","high":"2100","step":"10","tune":"1"},"unit":""} - ] - }, - {"idx":"1","enabled":"1","cursor":" ","prompt":"", - "pad":[ - {"idx":"0","enabled":"1","cursor":" ","prompt":"" ,"field":"0","range":{"low":"0","high":"23","step":"1","tune":"0"},"unit":":"}, - {"idx":"1","enabled":"1","cursor":" ","prompt":"" ,"field":"6","range":{"low":"0","high":"59","step":"10","tune":"1"},"unit":":"}, - {"idx":"2","enabled":"1","cursor":" ","prompt":"" ,"field":"33","range":{"low":"0","high":"59","step":"10","tune":"1"},"unit":""} - ] - }, - {"idx":"2","enabled":"1","cursor":" ","prompt":"GMT" ,"field":"-1","range":{"low":"-11","high":"12","step":"1","tune":"0"},"unit":""}, - {"idx":"3","enabled":"1","cursor":" ","prompt":"Sommerzeit:""tog":["options":[2]],"value":An,}, - {"idx":"4","enabled":"1","cursor":" ","prompt":"benutze NTP"}, - {"idx":"5","enabled":"1","cursor":" ","prompt":"Speichern"}, - {"idx":"6","enabled":"1","cursor":" ","prompt":"Zurück"} - ] - } + "menu":{"title":{"prompt":"Einstellungen"}, + ,"sel":"0","items":[ +{"idx":"0","enabled":"1","selStart":">""prompt":"Standby" ,"field":"5","range":{"low":"2","high":"5","step":"1","tune":"0"},"unit":"min."}, +{"idx":"1","enabled":"1","selStart":" ""prompt":"Key" ,"text":"QUYxMkJH" +}, +{"idx":"2","enabled":"1","selStart":" ""prompt":"Mondlicht" ,"type":"select"",options":["Aus","#1","#2","#3","#4","#5","#6"]#4}, +{"idx":"3","enabled":"1","selStart":" ""prompt":"max" ,"field":"1","range":{"low":"0","high":"100","step":"10","tune":"1"},"unit":"%"}, +{"idx":"4","enabled":"1","selStart":" ""prompt":"Wolken:","value":"Aus",options":["Aus","An"]}, +{"idx":"5","enabled":"1","selStart":" ""prompt":"max" ,"field":"50","range":{"low":"0","high":"100","step":"10","tune":"1"},"unit":"%"}, +{"idx":"6","enabled":"1","selStart":" ""prompt":"Gewitter:","value":"Aus",options":["Aus","An"]}, +{"idx":"7","enabled":"1","selStart":" ""prompt":"max" ,"field":"50","range":{"low":"0","high":"100","step":"10","tune":"1"},"unit":"%"}, +{"idx":"8","enabled":"1","selStart":" ""prompt":"Wi-Fi"}, +{"idx":"9","enabled":"1","selStart":" ""prompt":"Sprache" ,"type":"select"",options":["DE","EN","PT"]DE}, +{"idx":"10","enabled":"1","selStart":" ""prompt":"Aktualisieren..."}, +{"idx":"11","enabled":"1","selStart":" ""prompt":"Speichern"}, +{"idx":"12","enabled":"1","selStart":" ""prompt":"Zurück"} +] +} } From f979c00b2e4b3bc3fd58bf354b8774d64c3917d2 Mon Sep 17 00:00:00 2001 From: Rui Azevedo Date: Wed, 2 Jan 2019 03:24:17 -0100 Subject: [PATCH 020/197] cleanup --- src/menuIO/jsonFmt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/menuIO/jsonFmt.h b/src/menuIO/jsonFmt.h index 64412d66..f4814191 100644 --- a/src/menuIO/jsonFmt.h +++ b/src/menuIO/jsonFmt.h @@ -148,7 +148,7 @@ return proceed; } result fmtStart(prompt& target,menuOut::fmtParts part,navNode &nav,idx_t idx=-1) override { - _trace(printIndent();MENU_DEBUG_OUT<<">"<"< Date: Wed, 2 Jan 2019 04:24:17 -0100 Subject: [PATCH 021/197] cast (uint16_t) for travis --- examples/adafruitGfx/tft/tft/tft.ino | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/adafruitGfx/tft/tft/tft.ino b/examples/adafruitGfx/tft/tft/tft.ino index c72bd039..5907caa8 100644 --- a/examples/adafruitGfx/tft/tft/tft.ino +++ b/examples/adafruitGfx/tft/tft/tft.ino @@ -126,12 +126,12 @@ MENU(mainMenu,"Main menu",doNothing,noEvent,wrapStyle #define ST7735_GRAY RGB565(128,128,128) const colorDef colors[] MEMMODE={ - {{ST7735_BLACK,ST7735_BLACK},{ST7735_BLACK,ST7735_BLUE,ST7735_BLUE}},//bgColor - {{ST7735_GRAY,ST7735_GRAY},{ST7735_WHITE,ST7735_WHITE,ST7735_WHITE}},//fgColor - {{ST7735_WHITE,ST7735_BLACK},{ST7735_YELLOW,ST7735_YELLOW,ST7735_RED}},//valColor - {{ST7735_WHITE,ST7735_BLACK},{ST7735_WHITE,ST7735_YELLOW,ST7735_YELLOW}},//unitColor - {{ST7735_WHITE,ST7735_GRAY},{ST7735_BLACK,ST7735_BLUE,ST7735_WHITE}},//cursorColor - {{ST7735_WHITE,ST7735_YELLOW},{ST7735_BLUE,ST7735_RED,ST7735_RED}},//titleColor + {{(uint16_t)ST7735_BLACK,(uint16_t)ST7735_BLACK}, {(uint16_t)ST7735_BLACK, (uint16_t)ST7735_BLUE, (uint16_t)ST7735_BLUE}},//bgColor + {{(uint16_t)ST7735_GRAY, (uint16_t)ST7735_GRAY}, {(uint16_t)ST7735_WHITE, (uint16_t)ST7735_WHITE, (uint16_t)ST7735_WHITE}},//fgColor + {{(uint16_t)ST7735_WHITE,(uint16_t)ST7735_BLACK}, {(uint16_t)ST7735_YELLOW,(uint16_t)ST7735_YELLOW,(uint16_t)ST7735_RED}},//valColor + {{(uint16_t)ST7735_WHITE,(uint16_t)ST7735_BLACK}, {(uint16_t)ST7735_WHITE, (uint16_t)ST7735_YELLOW,(uint16_t)ST7735_YELLOW}},//unitColor + {{(uint16_t)ST7735_WHITE,(uint16_t)ST7735_GRAY}, {(uint16_t)ST7735_BLACK, (uint16_t)ST7735_BLUE, (uint16_t)ST7735_WHITE}},//cursorColor + {{(uint16_t)ST7735_WHITE,(uint16_t)ST7735_YELLOW},{(uint16_t)ST7735_BLUE, (uint16_t)ST7735_RED, (uint16_t)ST7735_RED}},//titleColor }; serialIn serial(Serial); From 59ad60ff5eb004b06f73036868c5e436cae33a20 Mon Sep 17 00:00:00 2001 From: Rui Azevedo Date: Fri, 4 Jan 2019 08:22:46 -0100 Subject: [PATCH 022/197] print path to json --- library.properties | 2 +- src/menuIO/jsonFmt.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index d65d988e..a61726f1 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ArduinoMenu library -version=4.15.0 +version=4.15.1 author=Rui Azevedo, ruihfazevedo@gmail.com maintainer=neu-rah, ruihfazevedo@gmail.com sentence=Generic menu/interactivity system diff --git a/src/menuIO/jsonFmt.h b/src/menuIO/jsonFmt.h index f4814191..156e7aee 100644 --- a/src/menuIO/jsonFmt.h +++ b/src/menuIO/jsonFmt.h @@ -37,7 +37,9 @@ break; case menuOut::fmtBody: if (start) { - *this<<",\"sel\":\""<printPath(*this,(menuNode*)&target); + *this<<"\",\"sel\":\""< Date: Sun, 6 Jan 2019 11:01:14 -0100 Subject: [PATCH 023/197] fixing webmenu --- examples/esp8266/WebMenu/WebMenu/WebMenu.ino | 313 ++++++++++++++---- .../WebMenu/WebMenu/data/1.0/bootstrap.xslt | 271 +++++++++++++++ .../WebMenu/WebMenu/data/{ => 1.0}/index.html | 0 .../esp8266/WebMenu/WebMenu/data/1.0/menu.css | 302 +++++++++++++++++ .../WebMenu/WebMenu/data/1.0/menu.xslt | 79 +++++ .../WebMenu/WebMenu/data/1.0/r-site.js | 187 +++++++++++ .../WebMenu/WebMenu/data/1.0/uTC360.xslt | 82 +++++ examples/esp8266/WebMenu/platformio.ini | 21 +- 8 files changed, 1183 insertions(+), 72 deletions(-) create mode 100644 examples/esp8266/WebMenu/WebMenu/data/1.0/bootstrap.xslt rename examples/esp8266/WebMenu/WebMenu/data/{ => 1.0}/index.html (100%) create mode 100644 examples/esp8266/WebMenu/WebMenu/data/1.0/menu.css create mode 100644 examples/esp8266/WebMenu/WebMenu/data/1.0/menu.xslt create mode 100644 examples/esp8266/WebMenu/WebMenu/data/1.0/r-site.js create mode 100644 examples/esp8266/WebMenu/WebMenu/data/1.0/uTC360.xslt diff --git a/examples/esp8266/WebMenu/WebMenu/WebMenu.ino b/examples/esp8266/WebMenu/WebMenu/WebMenu.ino index 798e4582..99c47407 100644 --- a/examples/esp8266/WebMenu/WebMenu/WebMenu.ino +++ b/examples/esp8266/WebMenu/WebMenu/WebMenu.ino @@ -24,10 +24,13 @@ so don't forget to change it. added textField (also experimental). */ + #include #include #include //to write a menu has html page #include +#include //to write a menu has xml page +#include //to write a menu has xml page // #include #include //#include //to send javascript thru web socket (live update) @@ -39,8 +42,14 @@ extern "C" { using namespace Menu; +#define CUR_VERSION 1.0 +bool fromWeb=false; +#define APName "WebMenu" #define ANALOG_PIN 4 +constexpr size_t wifiSSIDLen=64; +constexpr size_t wifiPwdLen=32; + #ifndef MENU_SSID #error "need to define WiFi SSID here" #define MENU_SSID "r-site.net" @@ -50,6 +59,48 @@ using namespace Menu; #define MENU_PASS "" #endif +char wifiSSID[wifiSSIDLen+1];//=" "; +char wifiPwd [wifiPwdLen+1];//=" "; + +// result wifiScan(eventMask event, navNode& nav, prompt &item) { +// int n=WiFi.scanNetworks(false); +// Serial.println(); +// nav.target->dirty=true; +// if (n == 0) { +// Serial.println("no network found.";Serial.flush(); +// nav.root->idleOn((idleFunc)noWifiFound); +// } else { +// prompt** nets=new prompt*[n+1]; +// for (int i = 0; i < n; ++i) { +// // Print SSID and RSSI for each network found +// char *ssid = new char[WiFi.SSID(i).length() + 1]; +// strcpy(ssid, WiFi.SSID(i).c_str()); +// // Serial.print(i + 1); +// // Serial.print(F(": ")); +// // Serial.print(ssid); +// // Serial.print(F(" (")); +// // Serial.print(WiFi.RSSI(i)); +// // Serial.print(F(")")); +// // Serial.println((WiFi.encryptionType(i) == WIFI_OPEN)?" ":"*"); +// nets[i]=new prompt(ssid,selectWifi,enterEvent); +// } +// nets[n]=(prompt*)&back; +// for (int i = 0; i < selNetworkMenu.sz()-1; i++) +// delItem(((menuNodeShadow*)selNetworkMenu.shadow)->data[i]); +// delete [] ((menuNodeShadow*)selNetworkMenu.shadow)->data; +// ((menuNodeShadow*)selNetworkMenu.shadow)->data=nets; +// ((menuNodeShadow*)selNetworkMenu.shadow)->sz=n+1; +// } +// // Serial.println(F("")); +// return proceed; +// } + +// SelNetMenu selNetworkMenu( +// lang[txtSSID], +// len(networkMenu_data), +// networkMenu_data,wifiScan,enterEvent,wrapStyle +// ); + const char* ssid = MENU_SSID; const char* password = MENU_PASS; const char* serverName="192.168.1.79"; @@ -74,9 +125,13 @@ ESP8266WebServer server(80); WebSocketsServer webSocket(81); #define MAX_DEPTH 2 -idx_t tops[MAX_DEPTH]; -PANELS(webPanels,{0,0,30,20}); -xmlFmt serverOut(server,tops,webPanels); +// idx_t tops[MAX_DEPTH]; +// PANELS(webPanels,{0,0,30,20}); +idx_t web_tops[MAX_DEPTH]; +PANELS(webPanels,{0,0,80,100}); +xmlFmt serverOut(server,web_tops,webPanels); +jsonFmt jsonOut(server,web_tops,webPanels); +jsonFmt wsOut(web_tops,webPanels); //menu action functions result action1(eventMask event, navNode& nav, prompt &item) { @@ -138,10 +193,33 @@ result idle(menuOut& o,idleEvent e) { return quit; } +template//some utill to help us calculate array sizes (known at compile time) +constexpr inline size_t len(T& o) {return sizeof(o)/sizeof(decltype(o[0]));} + +//serial menu navigation MENU_OUTLIST(out,&serverOut); serialIn serial(Serial); NAVROOT(nav,mainMenu,MAX_DEPTH,serial,out); +//xml+http navigation control +noInput none;//web uses its own API +menuOut* web_outputs[]={&serverOut}; +outputsList web_out(web_outputs,len(web_outputs)); +navNode web_cursors[MAX_DEPTH]; +navRoot webNav(mainMenu, web_cursors, MAX_DEPTH, none, web_out); + +//json+http navigation control +menuOut* json_outputs[]={&jsonOut}; +outputsList json_out(json_outputs,len(json_outputs)); +navNode json_cursors[MAX_DEPTH]; +navRoot jsonNav(mainMenu, json_cursors, MAX_DEPTH, none, json_out); + +//websockets navigation control +menuOut* ws_outputs[]={&wsOut}; +outputsList ws_out(ws_outputs,len(ws_outputs)); +navNode ws_cursors[MAX_DEPTH]; +navRoot wsNav(mainMenu, ws_cursors, MAX_DEPTH, none, ws_out); + //config myOptions('*','-',defaultNavCodes,false); void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { @@ -186,24 +264,55 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length } void pageStart() { - server.sendHeader("Cache-Control","no-cache, no-store, must-revalidate"); - server.sendHeader("Pragma","no-cache"); - server.sendHeader("Expires","0"); - serverOut - <<"\r\n" - "\r\n\r\n" - "" - <"; + _trace(Serial<<"pasgeStart!"<\r\n" + "\r\n\r\n"; + serverOut<<"\">\r\n"; + if (server.hasHeader("host")) + serverOut.print(server.header("host")); + else + serverOut.print(APName/*WiFi.localIP()*/); + serverOut<<""; } void pageEnd() { serverOut<<""; - server.send(200, "text/xml", serverOut.response); + server.client().stop(); } +// void pageStart() { +// server.sendHeader("Cache-Control","no-cache, no-store, must-revalidate"); +// server.sendHeader("Pragma","no-cache"); +// server.sendHeader("Expires","0"); +// serverOut +// <<"\r\n" +// "\r\n\r\n" +// "" +// <"; +// } +// +// void pageEnd() { +// serverOut<<""; +// server.send(200, "text/xml", serverOut.response); +// } + void handleNotFound(){ //digitalWrite(led, 1); Serial.println("404 not found"); @@ -223,49 +332,86 @@ void handleNotFound(){ //digitalWrite(led, 0); } -String getContentType(String filename){ - if(server.hasArg("download")) return "application/octet-stream"; - else if(filename.endsWith(".htm")) return "text/html"; - else if(filename.endsWith(".html")) return "text/html"; - else if(filename.endsWith(".css")) return "text/css"; - else if(filename.endsWith(".js")) return "application/javascript"; - else if(filename.endsWith(".png")) return "image/png"; - else if(filename.endsWith(".gif")) return "image/gif"; - else if(filename.endsWith(".jpg")) return "image/jpeg"; - else if(filename.endsWith(".ico")) return "image/x-icon"; - else if(filename.endsWith(".xml")) return "text/xml"; - else if(filename.endsWith(".xsl")) return "text/xml"; - else if(filename.endsWith(".xslt")) return "text/xsl"; - else if(filename.endsWith(".pdf")) return "application/x-pdf"; - else if(filename.endsWith(".zip")) return "application/x-zip"; - else if(filename.endsWith(".gz")) return "application/x-gzip"; - return "text/plain"; +// String getContentType(String filename){ +// if(server.hasArg("download")) return "application/octet-stream"; +// else if(filename.endsWith(".htm")) return "text/html"; +// else if(filename.endsWith(".html")) return "text/html"; +// else if(filename.endsWith(".css")) return "text/css"; +// else if(filename.endsWith(".js")) return "application/javascript"; +// else if(filename.endsWith(".png")) return "image/png"; +// else if(filename.endsWith(".gif")) return "image/gif"; +// else if(filename.endsWith(".jpg")) return "image/jpeg"; +// else if(filename.endsWith(".ico")) return "image/x-icon"; +// else if(filename.endsWith(".xml")) return "text/xml"; +// else if(filename.endsWith(".xsl")) return "text/xml"; +// else if(filename.endsWith(".xslt")) return "text/xsl"; +// else if(filename.endsWith(".pdf")) return "application/x-pdf"; +// else if(filename.endsWith(".zip")) return "application/x-zip"; +// else if(filename.endsWith(".gz")) return "application/x-gzip"; +// return "text/plain"; +// } + +// bool handleFileRead(String path){ +// if(path.endsWith("/")) path += "index.html"; +// String contentType = getContentType(path); +// String pathWithGz = path + ".gz"; +// if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)){ +// if(SPIFFS.exists(pathWithGz)) +// path += ".gz"; +// File file = SPIFFS.open(path, "r"); +// size_t sent = server.streamFile(file, contentType); +// file.close(); +// return true; +// } +// // Serial<<"file not found "<"; - serverOut<"; + serverOut<<""; + fromWeb=true; + webNav.doOutput(); + fromWeb=false; pageEnd(); - delay(1); + // handleMenu(); + // String r(serverOut.response); + // serverOut.response.remove(0); + // pageStart(); + // nav.doOutput(); + // serverOut<<""; + // serverOut<"; + // pageEnd(); + // delay(1); + }); + + //menu json server over http + server.on("/json", HTTP_GET, []() { + _trace(Serial<<"json request!"< + + + + + + + + + + + + +

+
+ + +
+
+ + +

+
+ + +
+
+ + +
  • + +
  • +
    + + + + + + + + + + / + + + + + + + + + + + + + + + + +
  • + +
  • +
    + +
  • + +
  • +
    +
    +
    + + +
    +
    + + +
  • + +
  • +
    + + + + + + + + + + + + + + + + + + + + / + + + + + + + + + + + / + + + + + + + + + + + + + + / + + + fld__ + fld__ + text + slider ledField + + + + + + + window.location='/menu?at='+getAttribute("data-src")+'/'+value + + + + + + + + / + + + + + + + + + + + + + + + + + + + + + 1 + 2 + 3 + 4 + 8 + + + + + + + + + + + + + + fld__ + fld__ + text + + + + + + + + + + menu-range-fld + range + + + window.location='/menu?at='+getAttribute("data-src")+'/'+value + + + + + fld__ + text + + + + + + form-control + + window.location='/menu?at='+getAttribute("data-src")+'/'+value + + + + + + + + + + + + fld__ + form-control + / + window.location.href='/menu?at='+getAttribute('data-src')+'/'+selectedIndex + + + + + + + + + + + + + + fld__ + + form-control + / + window.location='/menu?at='+getAttribute("data-src")+'/'+value + + + +
    diff --git a/examples/esp8266/WebMenu/WebMenu/data/index.html b/examples/esp8266/WebMenu/WebMenu/data/1.0/index.html similarity index 100% rename from examples/esp8266/WebMenu/WebMenu/data/index.html rename to examples/esp8266/WebMenu/WebMenu/data/1.0/index.html diff --git a/examples/esp8266/WebMenu/WebMenu/data/1.0/menu.css b/examples/esp8266/WebMenu/WebMenu/data/1.0/menu.css new file mode 100644 index 00000000..b5b9b91a --- /dev/null +++ b/examples/esp8266/WebMenu/WebMenu/data/1.0/menu.css @@ -0,0 +1,302 @@ +html, +body { + height: 100%; + background-color: #1d80e2; +} +body { + color: #fff; + text-align: center; + text-shadow: 0 1px 3px rgba(0,0,0,.5); + font-size: 18px; +} + +#outDlg .modal-content, .upForm { + background-color: #888 !important; + padding:1em; +} + +/* .masthead { + background-image: url(nav-bg.jpg); + background-size: cover; + background-position: center; +} */ + +nav { + background-color: #333; +} + +a { + text-decoration: none !important; +} + +input, select { + width: auto; + color: yellow; + background-color: transparent; + /* border: none; */ +} + +input[@type="uint32_t"] { + text-align: right; +} + +/* Links */ +a, +a:focus, +a:hover { + color: #fff; +} + +/* .asPad {background-color: gray;} */ +.pad-item {display: inline-block !important;} + +.form-control { + width:auto; + display:inline-block; +} + +.aml_op.btn {width:100%;} + +.actionBtn { + display:inline-block; + padding:1em; + background-color: #0ba6a4; + color: lime; + border: solid 1px lime; + border-radius: 3px; + text-align: right; +} + +/* Custom default button */ +.btn-default, +.btn-default:hover, +.btn-default:focus { + color: #333; + text-shadow: none; /* Prevent inheritance from `body` */ + background-color: #fff; + border: 1px solid #fff; +} + +input[type=range] { + display:inline-block !important; + width:auto !important; + background-color:#000800; +} + +/* + * Base structure + */ + +select {color: black;} + +/* Extra markup and styles for table-esque vertical and horizontal centering */ +.site-wrapper { + display: table; + width: 100%; + height: 100%; /* For at least Firefox */ + min-height: 100%; + -webkit-box-shadow: inset 0 0 100px rgba(0,0,0,.5); + box-shadow: inset 0 0 100px rgba(0,0,0,.5); +} +.site-wrapper-inner { + display: table-cell; + vertical-align: top; +} +.cover-container { + margin-right: auto; + margin-left: auto; +} + +/* Padding for spacing */ +/* .inner { + padding: 30px; +} */ + + +/* + * Header + */ +.masthead{ + background-color: #1d80e2; + height:150px; + overflow:hidden; + z-index:100; +} +/* .masthead-brand { + margin-top: 0px !important; +} */ +.masthead .wrap{ + -webkit-box-shadow: inset 0 0 100px rgba(0,0,0,.5); + box-shadow: inset 0 0 100px rgba(0,0,0,.5); + height:200px; +} + +.masthead .inner{ + /* padding:0 20px 0 60px; */ +} + +.masthead-brand { + margin-top: 0px; + padding-top: 0.5em; + margin-bottom: 0em; +} + +ul { + list-style-type: none; +} + +.masthead-nav > li { + display: inline-block; +} +.masthead-nav > li + li { + margin-left: 0.5em; +} +.masthead-nav > li > a { + padding-right: 0; + padding-left: 0; + font-size: 16px; + font-weight: bold; + color: #fff; /* IE8 proofing */ + color: rgba(255,255,255,.75); + border-bottom: 2px solid transparent; +} +.masthead-nav > li > a:hover, +.masthead-nav > li > a:focus { + background-color: transparent; + border-bottom-color: #a9a9a9; + border-bottom-color: rgba(255,255,255,.25); +} +.masthead-nav > .active > a, +.masthead-nav > .active > a:hover, +.masthead-nav > .active > a:focus { + color: #fff; + border-bottom-color: #fff; +} + +@media (min-width: 768px) { + .masthead{ + height:100px; + } + .masthead-brand { + float: left; + } + .masthead-nav { + margin-top: 1em; + float: right; + } +} + +/* + * Cover + */ + +.cover .btn-lg { + /* padding: 10px 20px; */ + font-weight: bold; +} + +.cover .btn-lg.linkBtn>a { + padding: 10px 20px; +} + +/* + * Footer + */ + +.mastfoot { + font-size: 0.6em; + color: #999; /* IE8 proofing */ + color: rgba(255,255,255,.5); + /* z-index: -1; */ +} + + +/* + * Affix and center + */ + +@media (min-width: 768px) { + /* Pull out the header and footer */ + .masthead { + position: fixed; + top: 0; + left: 0; + } + .mastfoot { + position: fixed; + bottom: 0; + } + /* Start the vertical centering */ + .site-wrapper-inner { + vertical-align: middle; + } + /* Handle the widths */ + .masthead, + .mastfoot, + .cover-container { + width: 100%; /* Must be percentage or pixels for horizontal alignment */ + } + .cover-container { + width: 700px; + } + .cover { + padding: 100px 1em 1em 1em !important; + } + +} + +@media (min-width: 992px) { + .masterhead { + padding: 1em; + } + .masthead .inner{ + margin: 0 auto; + } + .masthead .inner, + .mastfoot, + .cover-container { + width: 700px; + } + .cover { + padding: 100px 1em 1em 1em !important; + } +} + +.btn-active { + color: #fff; + background-color: #333; + border-color: #d58512; +} + +.btn-disabled { + color: #fff; + background-color: #696969; + border-color: #4cae4c; +} + +.slider { + margin-right:1em; + margin-left: 1em; +} + +.slider-selection { + background: #BABABA; +} + +.slider.slider-horizontal { + width:20% !important; +} + +.aml_op .del { + color:red; +} + +div.padOp {display:inline-block;} + +li.linkBtn {padding:0;} +li.linkBtn>a {display:block;margin:0;} + +.btn-space { + padding-left:0.5em; + padding-right:0.5em; +} diff --git a/examples/esp8266/WebMenu/WebMenu/data/1.0/menu.xslt b/examples/esp8266/WebMenu/WebMenu/data/1.0/menu.xslt new file mode 100644 index 00000000..ca39bfa1 --- /dev/null +++ b/examples/esp8266/WebMenu/WebMenu/data/1.0/menu.xslt @@ -0,0 +1,79 @@ + + + + + + + + http://neurux:8080/ + + + + + + + + + + + + + + AquaGrow - MicroTC360 + + + + + + + + + + + + +
    +
    +
    +
    +
    +
    +

    + Aqua-Grow +

    + +
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    +
    +
    + + +
    + +
    diff --git a/examples/esp8266/WebMenu/WebMenu/data/1.0/r-site.js b/examples/esp8266/WebMenu/WebMenu/data/1.0/r-site.js new file mode 100644 index 00000000..3917e022 --- /dev/null +++ b/examples/esp8266/WebMenu/WebMenu/data/1.0/r-site.js @@ -0,0 +1,187 @@ +// wsSrc = sourceURL; +wsSrc=window.location.hostname; +var connection = {}; + +// alert("r-site.js loaded!"); +var lastResult=null; +var previousResult=null; + +function connectWS() { + console.log("ws://" + wsSrc + ":81/", ["arduino"]); + connection = new WebSocket("ws://" + wsSrc + ":81/", ["arduino"]); + connection.onopen = init; + connection.onerror = function(e) {console.log("WebSocket Error ", e)}; + connection.onmessage = function(e) { + console.log(JSON.parse(e.data));//just for checking it + eval("lastResult="+e.data); + updatePage(); + }; + return connection.readyState; +} + +function updatePage() { + if (lastResult) mkPath(lastResult);//add path info + if (lastResult==previousResult) return; + if (previousResult&&lastResult.menu.title.prompt===previousResult.menu.title.prompt) + walkStates(lastResult.menu,previousResult.menu); + previousResult=lastResult; +} + +function refreshBtn(_,o) { + var p=$(o).attr("data-src"); + var g=$(o).attr("data-grp"); + var nv=jpath(g,lastResult.menu); + if (nv.value==$(o).text()) + console.log(p,g,nv); +} + +//get a single value out a menu state page by path +//it matches the page postion and selects requested item +//so path is absolute +function jpath(p,m) { + if (m.path!=p.slice(0,m.path.length)) return; + var ps=p.slice(m.path.length).split("/").slice(1); + return _jpath(m,ps); + function _jpath(m,o) { + var i=(m.pad||m.items) + if (!i&&o.length>0) return; + return (o.length&&i)?_jpath(i[o[0]],o.slice(1)):m + } +} + +//traverses previous and last state and +//update controls of changed values +function walkStates(i,j) { + if(!(i&&j)) return; + // console.log("walking states..."); + if (i.path!=j.path) return; + // console.log("path",i.path); + if (i.field&&j.field&&i.field!=j.field) {//numeric field! + var target=$("[data-src='"+i.path+"'"); + if (target.length) { + console.log("setting new field",i.path,i.field,target); + if (target.hasClass("slider")) target.slider("setValue",i.field); + else target.val(i.field); + } + } if (i.options&&j.options&&i.value!=j.value) {//enumerated field + var nvi=i.options.indexOf(i.value); + console.log("looking for",i.path); + var target=$("[data-src='"+i.path+"/"+nvi+"']"); + if (target.length) { + console.log("clicking on button"); + target.click(); + } else { + target=$("select[data-src='"+i.path+"']"); + if (target.length) { + console.log("changing selection",i.path,i.select); + target.val(i.select); + } + + } + } + if (typeof i[Symbol.iterator] === 'function'&&typeof j[Symbol.iterator] === 'function') + for(var n=0;n5) {//give up? + alert("websocket disconnected, please refresh page");//TODO: put mutilang here + return; + } else menu(o,cnt?cnt+1:0); + },500); + return; + } + console.log("send ws",o); + return connection.send(o); +} + +function updateField(e) { + return updateField_(e.target) +} + +function updateField_(e) { + var n = $(e).attr("data-src") + "/" + e.value + String.fromCharCode(255); + menu(n); +} + +function updateLink(e) { + return updateLink_(e.target) +} + +function updateLink_(e) { + var n = $(e), + o = n.attr("data-grp"), + t = n.attr("data-src"); + console.log("removing selections"); + $("a[data-grp='" + o + "']").removeClass("btn-primary btn-success"); + console.log("adding selection to", e); + n.addClass("btn-primary"); + console.log("sending: " + t); + menu(t); + // connection.send(t) +} + +function updateSelect(e) { + updateSelect_(e.target) +} + +function updateSelect_(e) { + var n = $(e).attr("data-src") + "/" + e.selectedIndex; + console.log("sending: " + n); + menu(n); + // connection.send(n); +} + +function init() { + console.log("menu websocket server connected."); + console.log("r-site menu page script starting."); + activePanel = $(".aml_panel"); + $(".aml_op>input").removeAttr("onchange").off("change").on("change", updateField); + $(".aml_op>select").removeAttr("onchange").off("change").on("change", updateSelect); + $("a.aml_btn").removeAttr("href").off("click").on("click", updateLink); + // $(".aml_op input.ledField").removeAttr("onchange").off("change").on("change", logField); +} +$(function() { + // console.log("ready!"); + connectWS(); + $("p.out").text() && $("#outDlg").modal(); + jQuery().slider && $(".slider").slider({formatter: function(e) {return e + "%"}}); +}); diff --git a/examples/esp8266/WebMenu/WebMenu/data/1.0/uTC360.xslt b/examples/esp8266/WebMenu/WebMenu/data/1.0/uTC360.xslt new file mode 100644 index 00000000..0a68580b --- /dev/null +++ b/examples/esp8266/WebMenu/WebMenu/data/1.0/uTC360.xslt @@ -0,0 +1,82 @@ + + + + + + + + + + + + +
  • + +
  • +
    + + + +
  • +
    + + download + +
  • +
    + + + + + + / + + + + btn-disabled + btn-success + + +
  • +
    +
    + +
  • +
    + + + + + + + + + + / + + + + + + + / + + + + +
    diff --git a/examples/esp8266/WebMenu/platformio.ini b/examples/esp8266/WebMenu/platformio.ini index 441d52a7..eeaf6704 100644 --- a/examples/esp8266/WebMenu/platformio.ini +++ b/examples/esp8266/WebMenu/platformio.ini @@ -19,9 +19,24 @@ data_dir=WebMenu/data ; framework = arduino ; build_flags = -Wno-comment -Wno-strict-aliasing -Wno-builtin-macro-redefined -DNODEBUG -[env:esp12e] +; [env:esp12e] +; platform = espressif8266 +; board = esp12e +; framework = arduino +; upload_speed=921600 +; build_flags = -DDEBUG -DMENU_ASYNC -DMENU_FMT_WRAPS + +[env:wemos] platform = espressif8266 -board = esp12e +board = d1_mini_lite framework = arduino +; upload_speed=1500000 upload_speed=921600 -build_flags = -DDEBUG -DMENU_ASYNC -DMENU_FMT_WRAPS -DMENU_SSID="\"r-site.net\"" -DMENU_PASS="\"rsite.2011\"" +upload_port=/dev/ttyUSB* +build_flags = + -DMENU_ASYNC + -DMENU_FMT_WRAPS + -DMENU_IDLE_BKGND + -DMENU_DEBUG + -DMENU_SSID="\"r-site.net\"" -DMENU_PASS="\"rsite.2011\"" +src_build_flags = !echo "-Wno-write-strings -Wno-reorder -Wno-strict-aliasing -Wno-sign-compare -DLOC="$PLATFORMIO_LOC From 76c76f9abe33a12abcbaa18992a1deced1e25ebf Mon Sep 17 00:00:00 2001 From: Rui Azevedo Date: Sun, 6 Jan 2019 13:37:05 -0100 Subject: [PATCH 024/197] webmenu examlples runs using platformio --- examples/esp8266/WebMenu/WebMenu/WebMenu.ino | 241 ++--------- .../esp8266/WebMenu/WebMenu/WebMenu.ino.cpp | 374 ++++++++++++++++++ .../WebMenu/WebMenu/data/1.0/bootstrap.xslt | 2 +- .../WebMenu/WebMenu/data/1.0/device.xslt | 11 + .../WebMenu/WebMenu/data/1.0/index.html | 12 +- .../WebMenu/WebMenu/data/1.0/menu.xslt | 30 +- .../WebMenu/WebMenu/data/1.0/uTC360.xslt | 82 ---- .../WebMenu/WebMenu/data/{ => img}/logo.png | Bin .../esp8266/WebMenu/WebMenu/data/menu.css | 185 --------- .../esp8266/WebMenu/WebMenu/data/menu.xslt | 139 ------- .../esp8266/WebMenu/WebMenu/data/r-site.js | 113 ------ examples/esp8266/WebMenu/platformio.ini | 7 +- 12 files changed, 461 insertions(+), 735 deletions(-) create mode 100644 examples/esp8266/WebMenu/WebMenu/WebMenu.ino.cpp create mode 100644 examples/esp8266/WebMenu/WebMenu/data/1.0/device.xslt delete mode 100644 examples/esp8266/WebMenu/WebMenu/data/1.0/uTC360.xslt rename examples/esp8266/WebMenu/WebMenu/data/{ => img}/logo.png (100%) delete mode 100644 examples/esp8266/WebMenu/WebMenu/data/menu.css delete mode 100644 examples/esp8266/WebMenu/WebMenu/data/menu.xslt delete mode 100644 examples/esp8266/WebMenu/WebMenu/data/r-site.js diff --git a/examples/esp8266/WebMenu/WebMenu/WebMenu.ino b/examples/esp8266/WebMenu/WebMenu/WebMenu.ino index 99c47407..1e4b938a 100644 --- a/examples/esp8266/WebMenu/WebMenu/WebMenu.ino +++ b/examples/esp8266/WebMenu/WebMenu/WebMenu.ino @@ -42,8 +42,24 @@ extern "C" { using namespace Menu; -#define CUR_VERSION 1.0 -bool fromWeb=false; +#ifdef WEB_DEBUG + // on debug mode I put aux files on external server to allow changes without SPIFF update + // on this mode the browser MUST be instructed to accept cross domain files + String xslt("http://neurux:8080/"); +#else + String xslt(""); +#endif + +menuOut& operator<<(menuOut& o,unsigned long int i) { + o.print(i); + return o; +} +menuOut& operator<<(menuOut& o,endlObj) { + o.println(); + return o; +} + +#define CUR_VERSION "1.0" #define APName "WebMenu" #define ANALOG_PIN 4 @@ -62,71 +78,17 @@ constexpr size_t wifiPwdLen=32; char wifiSSID[wifiSSIDLen+1];//=" "; char wifiPwd [wifiPwdLen+1];//=" "; -// result wifiScan(eventMask event, navNode& nav, prompt &item) { -// int n=WiFi.scanNetworks(false); -// Serial.println(); -// nav.target->dirty=true; -// if (n == 0) { -// Serial.println("no network found.";Serial.flush(); -// nav.root->idleOn((idleFunc)noWifiFound); -// } else { -// prompt** nets=new prompt*[n+1]; -// for (int i = 0; i < n; ++i) { -// // Print SSID and RSSI for each network found -// char *ssid = new char[WiFi.SSID(i).length() + 1]; -// strcpy(ssid, WiFi.SSID(i).c_str()); -// // Serial.print(i + 1); -// // Serial.print(F(": ")); -// // Serial.print(ssid); -// // Serial.print(F(" (")); -// // Serial.print(WiFi.RSSI(i)); -// // Serial.print(F(")")); -// // Serial.println((WiFi.encryptionType(i) == WIFI_OPEN)?" ":"*"); -// nets[i]=new prompt(ssid,selectWifi,enterEvent); -// } -// nets[n]=(prompt*)&back; -// for (int i = 0; i < selNetworkMenu.sz()-1; i++) -// delItem(((menuNodeShadow*)selNetworkMenu.shadow)->data[i]); -// delete [] ((menuNodeShadow*)selNetworkMenu.shadow)->data; -// ((menuNodeShadow*)selNetworkMenu.shadow)->data=nets; -// ((menuNodeShadow*)selNetworkMenu.shadow)->sz=n+1; -// } -// // Serial.println(F("")); -// return proceed; -// } - -// SelNetMenu selNetworkMenu( -// lang[txtSSID], -// len(networkMenu_data), -// networkMenu_data,wifiScan,enterEvent,wrapStyle -// ); - const char* ssid = MENU_SSID; const char* password = MENU_PASS; const char* serverName="192.168.1.79"; -#ifdef DEBUG - // on debug mode I put aux files on external server to allow changes without SPIFF update - // on this mode the browser MUST be instructed to accept cross domain files - #define xslt "http://neurux:8080/menu.xslt" -#else - #define xslt "/menu.xslt" - #define endl "\r\n" - menuOut& operator<<(menuOut&o, long unsigned int i) { - o.print(i); - return o; - } -#endif #define HTTP_PORT 80 #define WS_PORT 81 #define USE_SERIAL Serial -// ESP8266WiFiMulti WiFiMulti; ESP8266WebServer server(80); WebSocketsServer webSocket(81); #define MAX_DEPTH 2 -// idx_t tops[MAX_DEPTH]; -// PANELS(webPanels,{0,0,30,20}); idx_t web_tops[MAX_DEPTH]; PANELS(webPanels,{0,0,80,100}); xmlFmt serverOut(server,web_tops,webPanels); @@ -148,7 +110,7 @@ result action2(eventMask event, navNode& nav, prompt &item) { int ledCtrl=LOW; #define LEDPIN LED_BUILTIN void updLed() { - digitalWrite(LEDPIN,!ledCtrl); + //digitalWrite(LEDPIN,!ledCtrl); } TOGGLE(ledCtrl,setLed,"Led: ",updLed,enterEvent,noStyle//,doExit,enterEvent,noStyle @@ -173,7 +135,7 @@ CHOOSE(chooseTest,chooseMenu,"Choose",doNothing,noEvent,noStyle int timeOn=50; void updAnalog() { - analogWrite(ANALOG_PIN,map(timeOn,0,100,0,255/*PWMRANGE*/)); + // analogWrite(ANALOG_PIN,map(timeOn,0,100,0,255/*PWMRANGE*/)); } //the menu @@ -260,6 +222,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length //Serial<\r\n" "\r\n\r\n"; - serverOut<<"\">\r\n"; + serverOut.print(APName); + serverOut<<"\">\r\n"; if (server.hasHeader("host")) serverOut.print(server.header("host")); else - serverOut.print(APName/*WiFi.localIP()*/); + serverOut.print(APName); serverOut<<""; } @@ -294,107 +256,16 @@ void pageEnd() { server.client().stop(); } -// void pageStart() { -// server.sendHeader("Cache-Control","no-cache, no-store, must-revalidate"); -// server.sendHeader("Pragma","no-cache"); -// server.sendHeader("Expires","0"); -// serverOut -// <<"\r\n" -// "\r\n\r\n" -// "" -// <"; -// } -// -// void pageEnd() { -// serverOut<<""; -// server.send(200, "text/xml", serverOut.response); -// } - -void handleNotFound(){ - //digitalWrite(led, 1); - Serial.println("404 not found"); - String message = "File Not Found\n\n"; - message += "URI: "; - message += server.uri(); - message += "\nMethod: "; - message += (server.method() == HTTP_GET)?"GET":"POST"; - message += "\nArguments: "; - message += server.args(); - message += "\n"; - for (uint8_t i=0; i
    "; - fromWeb=true; webNav.doOutput(); - fromWeb=false; pageEnd(); - // handleMenu(); - // String r(serverOut.response); - // serverOut.response.remove(0); - // pageStart(); - // nav.doOutput(); - // serverOut<<""; - // serverOut<"; - // pageEnd(); - // delay(1); }); //menu json server over http @@ -510,29 +362,22 @@ void setup(){ serverOut<<"{\"output\":\""; handleMenu(jsonNav); serverOut<<"\",\n\"menu\":"; - fromWeb=true; jsonNav.doOutput(); - fromWeb=false; serverOut<<"\n}"; jsonEnd(); }); - //file server, if MDNS handler not found. - //so, do not put sensitive info in the data files - // server.onNotFound([](){if (!handleFileRead(server.uri())) notfound();}); - server.begin(); Serial.println("HTTP server started"); Serial.println("Serving ArduinoMenu example."); - #ifdef uTC_DEBUG - server.serveStatic("/", SPIFFS, "/","max-age=30");//31536000"); + #ifdef MENU_DEBUG + server.serveStatic("/", SPIFFS, "/","max-age=30"); #else server.serveStatic("/", SPIFFS, "/","max-age=31536000"); #endif } void loop(void){ - // serverOut.response.remove(0); wsOut.response.remove(0);//clear websocket json buffer webSocket.loop(); server.handleClient(); diff --git a/examples/esp8266/WebMenu/WebMenu/WebMenu.ino.cpp b/examples/esp8266/WebMenu/WebMenu/WebMenu.ino.cpp new file mode 100644 index 00000000..d538b5e8 --- /dev/null +++ b/examples/esp8266/WebMenu/WebMenu/WebMenu.ino.cpp @@ -0,0 +1,374 @@ +# 1 "/tmp/tmpTgRVqU" +#include +# 1 "/home/azevedo/Sketchbook/LIBDEV/ArduinoMenu/examples/esp8266/WebMenu/WebMenu/WebMenu.ino" +# 28 "/home/azevedo/Sketchbook/LIBDEV/ArduinoMenu/examples/esp8266/WebMenu/WebMenu/WebMenu.ino" +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +extern "C" { + #include "user_interface.h" +} + +using namespace Menu; + +#ifdef WEB_DEBUG + + + String xslt("http://neurux:8080/"); +#else + String xslt(""); +#endif + +menuOut& operator<<(menuOut& o,unsigned long int i) { + o.print(i); + return o; +} +menuOut& operator<<(menuOut& o,endlObj) { + o.println(); + return o; +} + +#define CUR_VERSION "1.0" +#define APName "WebMenu" +#define ANALOG_PIN 4 + +constexpr size_t wifiSSIDLen=64; +constexpr size_t wifiPwdLen=32; + +#ifndef MENU_SSID + #error "need to define WiFi SSID here" + #define MENU_SSID "r-site.net" +#endif +#ifndef MENU_PASS + #error "need to define WiFi password here" + #define MENU_PASS "" +#endif + +char wifiSSID[wifiSSIDLen+1]; +char wifiPwd [wifiPwdLen+1]; + +const char* ssid = MENU_SSID; +const char* password = MENU_PASS; +const char* serverName="192.168.1.79"; + +#define HTTP_PORT 80 +#define WS_PORT 81 +#define USE_SERIAL Serial +ESP8266WebServer server(80); +WebSocketsServer webSocket(81); + +#define MAX_DEPTH 2 +idx_t web_tops[MAX_DEPTH]; +PANELS(webPanels,{0,0,80,100}); +xmlFmt serverOut(server,web_tops,webPanels); +jsonFmt jsonOut(server,web_tops,webPanels); +jsonFmt wsOut(web_tops,webPanels); +result action1(eventMask event, navNode& nav, prompt &item); +result action2(eventMask event, navNode& nav, prompt &item); +void updLed(); +void updAnalog(); +result idle(menuOut& o,idleEvent e); +void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length); +void pageStart(); +void pageEnd(); +void jsonStart(); +void jsonEnd(); +bool handleMenu(navRoot& nav); +void setup(); +void loop(void); +#line 99 "/home/azevedo/Sketchbook/LIBDEV/ArduinoMenu/examples/esp8266/WebMenu/WebMenu/WebMenu.ino" +result action1(eventMask event, navNode& nav, prompt &item) { + Serial.println("action A called!"); + serverOut<<"This is action A web report "<<(millis()%1000)<<"
    "; + return proceed; +} +result action2(eventMask event, navNode& nav, prompt &item) { + Serial.println("action B called!"); + serverOut<<"This is action B web report "<<(millis()%1000)<<"
    "; + return proceed; +} + +int ledCtrl=LOW; +#define LEDPIN LED_BUILTIN +void updLed() { + +} + +TOGGLE(ledCtrl,setLed,"Led: ",updLed,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) +); + +int timeOn=50; +void updAnalog() { + +} + + +MENU(mainMenu,"Main menu",doNothing,noEvent,wrapStyle + ,SUBMENU(setLed) + ,OP("Action A",action1,enterEvent) + ,OP("Action B",action2,enterEvent) + ,FIELD(timeOn,"On","ms",0,100,10,1, updAnalog, anyEvent, noStyle) + ,SUBMENU(selMenu) + ,SUBMENU(chooseMenu) +); + +result idle(menuOut& o,idleEvent e) { + + Serial.println("suspended"); + o<<"suspended..."< +constexpr inline size_t len(T& o) {return sizeof(o)/sizeof(decltype(o[0]));} + + +MENU_OUTLIST(out,&serverOut); +serialIn serial(Serial); +NAVROOT(nav,mainMenu,MAX_DEPTH,serial,out); + + +noInput none; +menuOut* web_outputs[]={&serverOut}; +outputsList web_out(web_outputs,len(web_outputs)); +navNode web_cursors[MAX_DEPTH]; +navRoot webNav(mainMenu, web_cursors, MAX_DEPTH, none, web_out); + + +menuOut* json_outputs[]={&jsonOut}; +outputsList json_out(json_outputs,len(json_outputs)); +navNode json_cursors[MAX_DEPTH]; +navRoot jsonNav(mainMenu, json_cursors, MAX_DEPTH, none, json_out); + + +menuOut* ws_outputs[]={&wsOut}; +outputsList ws_out(ws_outputs,len(ws_outputs)); +navNode ws_cursors[MAX_DEPTH]; +navRoot wsNav(mainMenu, ws_cursors, MAX_DEPTH, none, ws_out); + + + +void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { + switch(type) { + case WStype_DISCONNECTED: + + break; + case WStype_CONNECTED: { + IPAddress ip = webSocket.remoteIP(num); + + webSocket.sendTXT(num, "console.log('ArduinoMenu Connected')"); + } + break; + case WStype_TEXT: + + nav.async((const char*)payload); + break; + case WStype_BIN: { + USE_SERIAL<<"[WSc] get binary length:"<\r\n" + "\r\n\r\n"; + if (server.hasHeader("host")) + serverOut.print(server.header("host")); + else + serverOut.print(APName); + serverOut<<""; +} + +void pageEnd() { + serverOut<<""; + server.client().stop(); +} + +void jsonStart() { + _trace(Serial<<"jsonStart!"< 0; t--) { + Serial.printf("[SETUP] BOOT WAIT %d...\n", t); + Serial.flush(); + delay(1000); + } + + + + + + + Serial.println(""); + Serial.println("Arduino menu webserver example"); + + SPIFFS.begin(); + + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + webSocket.begin(); + Serial.println(""); + webSocket.onEvent(webSocketEvent); + Serial.println("Connected."); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + webSocket.begin(); + + nav.idleTask=idle; + + server.on("/",HTTP_GET,mainPage); + + + server.on("/menu", HTTP_GET, []() { + pageStart(); + serverOut<<""; + webNav.doOutput(); + pageEnd(); + }); + + + server.on("/json", HTTP_GET, []() { + _trace(Serial<<"json request!"<