neu-rah / ArduinoMenu

Arduino generic menu/interactivity system
GNU Lesser General Public License v2.1
943 stars 191 forks source link

Need tutorial on adding new input or output devices #234

Open fovea1959 opened 5 years ago

fovea1959 commented 5 years ago

I am trying to evaluate adapting ArduinoMenu to run under Mongoose OS, and am looking at a two stage implementation plan:

1) get it running on Linux (with a very generic serial input and output device, similar to the Blink or Button examples). I want to do this so I can quickly get the menus going, and make sure I really understand what's going on.

2) move it to Mongoose OS (with an ILI9341 output and some pushbutton inputs).

I have looked at some of the existing input and output drivers, and issues #75 and #221, and they kind of make sense. Is there a simple tutorial on how to write a simple input or output for ArduinoMenu?

neu-rah commented 5 years ago

Nope there no such tutorial yet, maybe its time for one. Input can be done using navigation commands to cover virtually any input type, drivers are just a commodity, codeCtrl example may make it clear https://github.com/neu-rah/ArduinoMenu/blob/master/examples/codeCtrl/codeCtrl/codeCtrl.ino#L169

I'm a linux user, but right now I have no idea what need to be done to put it eunning out of arduino framework, but I'm definitively interested, please join us on gitter chat room https://gitter.im/ArduinoMenu/Lobby

fovea1959 commented 5 years ago

I don't need async for this (I'm already running in a polled environment), so that may simplify things.

The pointer to codeCtrl.ino works for me for the input side. Being able to do a real menuIn would be nice, but I think this should suffice.

For output is that I need to implement a subclass of menuOut (or one of it's subclasses cursorOut or gfxOut, depending on my output device capability), and I should be good to go?

I'd love to join you on gitter, but doing that is going to allow gitter to have access to some organization data in github that I am not comfortable sharing. I have no problem with allowing gitter access to my information, but I don't own the other, so can't do that :(

neu-rah commented 5 years ago

No problem, I was looking at Mongoose OS, it seems very interesting! Gotta dig deeper and check it.

Yes, menuOut is the output base, gfxOut provides a nicer approach to graphics display/libraries so I think its the starting point. Most examples use macros to define IO and hide the ugly details, you will probably want to look at noMacros example to see how things get together behind the also ugly macros (https://github.com/neu-rah/ArduinoMenu/blob/master/examples/noMacros/noMacros/noMacros.ino#L63) or here (https://github.com/neu-rah/ArduinoMenu/blob/master/examples/SSD1306Ascii/SSD1306Ascii/SSD1306Ascii.ino#L162) where SD1306Ascii output is being defined without the macros.

There are also outputs to JSON and XML formats that overlay a text output, I like this technique so much that it should have been the base (c++ template mixins).

I would like to help on this, but i'm still not sure where to start, but I'm sure Mongoose has interesting stuff.

On this menu, some things have been implemented out of order as the project has grown (I'm one of the worst critics). But also some stuff is worth to keep and it is doing amazing things as is. I've been exploring some ideas for version 5, Moongose looks good, wonder if you guys have some sort of RPC or commands table like this one (https://github.com/rleddy/tinycmdtable). AM provides it but organized by menus.

Feel free to contact me by email also.

fovea1959 commented 5 years ago

Thanks for the tips, those are helpful.

I'll take the bare minimum over to a Mongoos/ESP32 project on Monday and start hacking on it. I'll pull the existing repo, and I'll leave mine public.

On Friday, February 15, 2019, 12:52:59 PM EST, Rui Azevedo <notifications@github.com> wrote:  

No problem, I was looking at Mongoose OS, it seems very interesting! Gotta dig deeper and check it.

Yes, menuOut is the output base, gfxOut provides a nicer approach to graphics display/libraries so I think its the starting point. Most examples use macros to define IO and hide the ugly details, you will probably want to look at noMacros example to see how things get together behind the also ugly macros (https://github.com/neu-rah/ArduinoMenu/blob/master/examples/noMacros/noMacros/noMacros.ino#L63) or here (https://github.com/neu-rah/ArduinoMenu/blob/master/examples/SSD1306Ascii/SSD1306Ascii/SSD1306Ascii.ino#L162) where SD1306Ascii output is being defined without the macros.

There are also outputs to JSON and XML formats that overlay a text output, I like this technique so much that it should have been the base (c++ template mixins).

I would like to help on this, but i'm still not sure where to start, but I'm sure Mongoose has interesting stuff.

On this menu, some things have been implemented out of order as the project has grown (I'm one of the worst critics). But also some stuff is worth to keep and it is doing amazing things as is. I've been exploring some ideas for version 5, Moongose looks good, wonder if you guys have some sort of RPC or commands table like this one (https://github.com/rleddy/tinycmdtable). AM provides it but organized by menus.

Feel free to contact me by email also.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

neu-rah commented 5 years ago

nice, on this side i'm aiming to compile this as a console app (on linux), or at least see what is needed.

fovea1959 commented 5 years ago

ok, I'll let you work through the console app. Please let me know if the changes you need to make to get it build; those will be the same places I need to look at. (#include "Arduino.h")

On Friday, February 15, 2019, 2:18:18 PM EST, Rui Azevedo <notifications@github.com> wrote:  

nice, on this side i'm aiming to compile this as a console app (on linux), or at least see what is needed.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

neu-rah commented 5 years ago

Ok made it compile and run as linux console app the dirtiest way... pushing to new linuxOS branch

arduino dependencies hack all in src/naf folder, i just grabbed the arduino-core sources for String, Stream, Print and Printable and removed some PGM stuff. Also some numeric to text non-standard functions added to extra.h as well as millis (menu manages timeouts/sleep)

this dependencies can be replaced by classes that take a better advantage of std iostream and string, but for a quick hack its ok and working.

here is the code i've used to test it:

#include <iostream>

using namespace std;

#include <menu.h>
#include <menuIO/serialOut.h>
#include <menuIO/serialIn.h>

using namespace Menu;

//define "Op 1"
void op1Func();
constMEM char op1Text[] MEMMODE="Op 1";
constMEM promptShadowRaw op1InfoRaw MEMMODE={(callback)op1Func,_noStyle,op1Text,enterEvent,noStyle};
constMEM promptShadow& op1Info=*(promptShadow*)&op1InfoRaw;
//or just this line on non AVR devices like teensy or esp8266 instead of the above three
//promptShadow op1Info("Op 1",(callback)op1Func,enterEvent);
prompt op1(op1Info);

//define "Op 2"
void op2Func();
constMEM char op2Text[] MEMMODE="Op 2";
constMEM promptShadowRaw op2InfoRaw MEMMODE={(callback)op2Func,_noStyle,op2Text,enterEvent,noStyle};
constMEM promptShadow& op2Info=*(promptShadow*)&op2InfoRaw;
//or just this line on non MEMMODE devices like teensy or esp8266 instead of the above three
//promptShadow op2Info("Op 2",(callback)op2Func,enterEvent);
prompt op2(op2Info);

//define the menu
prompt* constMEM menuData[] MEMMODE={&op1,&op2};
//or just prompt* menuData[]={&op1,&op2}; on non avr devices
constMEM char menuTitle[] MEMMODE="Main menu";
constMEM menuNodeShadowRaw menuInfoRaw MEMMODE={
  (callback)doNothing,
  (systemStyles)(_menuData|_canNav),
  menuTitle,
  noEvent,
  wrapStyle,
  sizeof(menuData)/sizeof(prompt*),
  menuData
};
constMEM menuNodeShadow& menuInfo=*(menuNodeShadow*)&menuInfoRaw;
//or just this line on non AVR devices like teensy or esp8266 instead of the above three
//menuNodeShadow menuInfo("Main menu",2,menuData,(callback)doNothing,noEvent,wrapStyle);
menuNode mainMenu(menuInfo);

#define MAX_DEPTH 1

//define input device
noInput none;//dumb input device

//define output device
// idx_t serialTops[MAX_DEPTH]={0};
// serialOut outSerial(Serial,serialTops);

template<ostream& device>
class consoleOut:public menuOut {
  public:
    //ostream& device;
    idx_t lastLine=-1;
    inline consoleOut(idx_t* t,panelsList &p=default_serial_panel_list,menuOut::styles st=menuOut::none)
      :menuOut(t,p,(menuOut::styles)(st|menuOut::drawNumIndex))/*,device(o)*/ {}
    size_t write(uint8_t ch) override {
      device<<ch;
      return 1;
    }
    void clear() override {
      println();
      panels.reset();
    }
    void clear(idx_t panelNr) override {
      trace(MENU_DEBUG_OUT<<"serialOut::clear(idx_t panelNr)"<<endl;)
      trace(MENU_DEBUG_OUT.flush());
      println();
      panels.nodes[panelNr]=NULL;
    }
    void clearLine(
      idx_t ln,
      idx_t panelNr=0,
      colorDefs color=bgColor,
      bool selected=false,
      status stat=enabledStatus,
      bool edit=false
    ) override {
      lastLine=-1;
      //device.println();
      device<<endl;
    }
    void setCursor(idx_t x,idx_t y,idx_t panelNr=0) override {
      if (lastLine>=0&&lastLine!=y) println();
      lastLine=y;
    };
};

idx_t consoleTops[MAX_DEPTH]{0};
consoleOut<cout> outCon(consoleTops);

//define outputs controller
menuOut* constMEM outputs[] MEMMODE={&outCon};//list of output devices
outputsList out(outputs,1);//outputs list controller

//define navigation root and aux objects
navNode nav_cursors[MAX_DEPTH];//aux objects to control each level of navigation
navRoot nav(mainMenu, nav_cursors, MAX_DEPTH, none, out);

//implement the menu actions
void op1Func() {cout<<"Op 1 executed"<<endl;}
void op2Func() {cout<<"Op 2 executed"<<endl;}

/////////////////////////////////////////////////////////////////////////////
// arduino sketch
void setup() {
  cout<<"ArduinoMenu as console app."<<endl;
}

void loop() {
  nav.poll();
  char ch=cin.get();
  switch(ch) {
    case '+':nav.doNav(upCmd);break;
    case '-':nav.doNav(downCmd);break;
    case '*':nav.doNav(enterCmd);break;
    case '/':nav.doNav(escCmd);break;
  }
  //delay(100);
}

int main(int,char**) {
  setup();
  while(true) loop();
  return 0;
}

ignore the makefile, this attempt to compile it as a proper library was taking too much time, long time i don't write makefiles by hand :D, instead i've compiled all needed sources with this:

#!/bin/sh
echo ====================================================================================
g++ conioMenu/conioMenu.cpp\
  ~/Sketchbook/LIBDEV/ArduinoMenu/src/items.cpp\
  ~/Sketchbook/LIBDEV/ArduinoMenu/src/itemsTemplates.cpp\
  ~/Sketchbook/LIBDEV/ArduinoMenu/src/menuBase.cpp\
  ~/Sketchbook/LIBDEV/ArduinoMenu/src/menu.cpp\
  ~/Sketchbook/LIBDEV/ArduinoMenu/src/menuIo.cpp\
  ~/Sketchbook/LIBDEV/ArduinoMenu/src/nav.cpp\
  ~/Sketchbook/LIBDEV/ArduinoMenu/src/menuIO/serialOut.cpp\
  ~/Sketchbook/LIBDEV/ArduinoMenu/src/naf/Print.cpp\
  ~/Sketchbook/LIBDEV/ArduinoMenu/src/naf/Stream.cpp\
  ~/Sketchbook/LIBDEV/ArduinoMenu/src/naf/WString.cpp\
  -o.out/conioMenu\
  -I/home/azevedo/Sketchbook/LIBDEV/ArduinoMenu/src\
  -I/home/azevedo/Sketchbook/LIBDEV/ArduinoMenu/src/menuIO\
  -I/home/azevedo/Sketchbook/LIBDEV/ArduinoMenu/src/naf\
  -L/home/azevedo/Sketchbook/LIBDEV/ArduinoMenu/out/am4.a\
  -std=c++11\
  -Wno-endif-labels
fovea1959 commented 5 years ago

Confirmed working. Will work on porting to Mongoose + ILI9341.

TerryKing commented 4 years ago

Hi, I have a working application using earlier version 2 in which I used a 5-button analog (resistor array) keyboard. I need an example of using the same keyboard in the new version. THIS Keyboard: http://www.yourduino.com/sunshop/index.php?l=product_detail&p=334 Do not see same .H files! Here is what I did for that keyboard in the early version:

include // define our 5-button Analog keyboard

/-----------( Read analog values from 4-button keyboard, decode voltages to Buttons )---------------/ int getButton() { int i, v, button; int sum = 0;

for (i = 0; i < 4; i++) { sum += analogRead(keyboard_AnalogInput); } v = sum / 4; if (v > 1000) button = 0; else if (v >= 0 && v < 20) button = 1; //LEFT else if (v > 135 && v < 155) button = 2; //UP else if (v > 315 && v < 335) button = 3; //DOWN else if (v > 495 && v < 515) button = 4; //RIGHT else if (v > 725 && v < 745) button = 5; //ENTER else button = 0; // Serial.println(button); // For test return button; }// END getButton

/-------------------( Debounce keystrokes, translate to ArduinoMenu buttons )-------------------/ int old_button = 0; int read_keyboard() { int button, button2, pressed_button; button = getButton(); // Above if (button != old_button) // A new button pressed { delay(50); // debounce button2 = getButton(); if (button == button2) { old_button = button; pressed_button = button; if (button != 0) { //Serial.println(button); if (button == 1) return btnLEFT; if (button == 2) return btnUP; if (button == 3) return btnDOWN; if (button == 4) return btnRIGHT; if (button == 5) return btnENTER; } } } else { return btnNONE; } }// End read_keyboard

neu-rah commented 4 years ago

@TerryKing, offtopic, please open a new issue. you can use any input type when using the navigation commands, see example here https://github.com/neu-rah/ArduinoMenu/blob/master/examples/codeCtrl/codeCtrl/codeCtrl.ino#L172