neu-rah / ArduinoMenu

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

Full graphic smart controller - cannot get the ecnoder to scroll nicely #421

Open dumitrugrl opened 11 months ago

dumitrugrl commented 11 months ago

Hi, I am trying to get the menu to work with the RepRap Full Graphic Smart Controller: https://reprap.org/wiki/RepRapDiscount_Full_Graphic_Smart_Controller.

It displays the menu, but in order to scroll I need to turn the encoder rapidly and many times just to move to the next item. Does anyone have a simple working example for this setup: Mega 2560 + Ramps 1.4 + REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER.

#include <Arduino.h>

/********************
Arduino generic menu system
U8GLib menu example
U8Glib: https://github.com/olikraus/U8glib_Arduino

Jul.2016 Rui Azevedo - ruihfazevedo(@rrob@)gmail.com
Original from: https://github.com/christophepersoz

menu on U8GLib device
output: Nokia 5110 display (PCD8544 HW SPI) + Serial
input: Serial + encoder

ESP8266 Compile Error:
  `.irom0.text' will not fit in region `irom0_0_seg'
  see: http://bbs.espressif.com/viewtopic.php?t=166

please use U8G2 instead.

*/

#include <U8glib.h>
#include <menu.h>
// #include <menuIO/encoderIn.h>
#include <ClickEncoder.h>
#include <menuIO/clickEncoderIn.h>
#include <menuIO/keyIn.h>
#include <menuIO/chainStream.h>
// #include <menuIO/rotaryEventIn.h>
#include <menuIO/serialOut.h>
#include <menuIO/serialIn.h>
#include <menuIO/U8GLibOut.h>
#include <TimerOne.h>

using namespace Menu;

// #define INT_MODE_TYPE uint8_t

#define LEDPIN LED_BUILTIN

// Standard pins when on a RAMPS 1.4
#define DOGLCD_CS 16
#define DOGLCD_MOSI 17
#define DOGLCD_SCK 23
#define BTN_EN1 31
#define BTN_EN2 33
#define BTN_ENC 35
#define SD_DETECT_PIN 49
#define SDSS 53
#define BEEPER_PIN 37
#define KILL_PIN 41

// SPI Com: SCK = en = 23, MOSI = rw = 17, CS = di = 16
U8GLIB_ST7920_128X64_1X u8g(DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS);

// rotary encoder pins
#define encA 31   // 2
#define encB 33   // 3
#define encBtn 35 // 4

// #define U8_DC 9
// #define U8_CS 8
// #define U8_RST 7
// U8GLIB_PCD8544 u8g(U8_CS, U8_DC, U8_RST);

result doAlert(eventMask e, prompt &item);

result showEvent(eventMask e, navNode &nav, prompt &item)
{
  Serial.print("event: ");
  Serial.println(e);
  return proceed;
}

int test = 55;

result action1(eventMask e)
{
  Serial.print(e);
  Serial.println(" action1 executed, proceed menu");
  Serial.flush();
  return proceed;
}

result action2(eventMask e, navNode &nav, prompt &item)
{
  Serial.print(e);
  Serial.print(" action2 executed, quiting menu");
  return quit;
}

int ledCtrl = LOW;

result myLedOn()
{
  ledCtrl = HIGH;
  return proceed;
}
result myLedOff()
{
  ledCtrl = LOW;
  return proceed;
}

TOGGLE(ledCtrl, setLed, "Led: ", doNothing, noEvent, noStyle, VALUE("On", HIGH, doNothing, noEvent), VALUE("Off", LOW, doNothing, noEvent));

int selTest = 0;
SELECT(selTest, selMenu, "Select", doNothing, noEvent, noStyle, VALUE("Zero", 0, doNothing, noEvent), VALUE("One", 1, doNothing, noEvent), VALUE("Two", 2, doNothing, noEvent));

int chooseTest = -1;
CHOOSE(chooseTest, chooseMenu, "Choose", doNothing, noEvent, noStyle, VALUE("First", 1, doNothing, noEvent), VALUE("Second", 2, doNothing, noEvent), VALUE("Third", 3, doNothing, noEvent), VALUE("Last", -1, doNothing, noEvent));

// customizing a prompt look!
// by extending the prompt class
class altPrompt : public prompt
{
public:
  altPrompt(constMEM promptShadow &p) : prompt(p) {}
  Used printTo(navRoot &root, bool sel, menuOut &out, idx_t idx, idx_t len, idx_t panelNr) override
  {
    return out.printRaw(F("special prompt!"), len);
    ;
  }
};

MENU(subMenu, "Sub-Menu", showEvent, anyEvent, noStyle, OP("Sub1", showEvent, anyEvent), OP("Sub2", showEvent, anyEvent), OP("Sub3", showEvent, anyEvent), altOP(altPrompt, "", showEvent, anyEvent), EXIT("<Back"));

const char *constMEM hexDigit MEMMODE = "0123456789ABCDEF";
const char *constMEM hexNr[] MEMMODE = {"0", "x", hexDigit, hexDigit};
char buf1[] = "0x11";

MENU(mainMenu, "Main menu", doNothing, noEvent, wrapStyle, OP("Op1", action1, anyEvent), OP("Op2", action2, enterEvent), FIELD(test, "Test", "%", 0, 100, 10, 1, doNothing, noEvent, wrapStyle), EDIT("Hex", buf1, hexNr, doNothing, noEvent, noStyle), SUBMENU(subMenu), SUBMENU(setLed), OP("LED On", myLedOn, enterEvent), OP("LED Off", myLedOff, enterEvent), SUBMENU(selMenu), SUBMENU(chooseMenu), OP("Alert test", doAlert, enterEvent), EXIT("<Back"));

// define menu colors --------------------------------------------------------
// each color is in the format:
//  {{disabled normal,disabled selected},{enabled normal,enabled selected, enabled editing}}
// this is a monochromatic color table
const colorDef<uint8_t> colors[6] MEMMODE = {
    {{0, 0}, {0, 1, 1}}, // bgColor
    {{1, 1}, {1, 0, 0}}, // fgColor
    {{1, 1}, {1, 0, 0}}, // valColor
    {{1, 1}, {1, 0, 0}}, // unitColor
    {{0, 1}, {0, 0, 1}}, // cursorColor
    {{0, 0}, {1, 1, 1}}, // titleColor
};

// encoderIn<encA, encB> encoder;                     // simple quad encoder driver
// encoderInStream<encA, encB> encStream(encoder, 1); // simple quad encoder fake Stream

// Create encoder instance
ClickEncoder *encoder;
// Value of encoder
int16_t last, value;

ClickEncoder clickEncoder(BTN_EN1, BTN_EN2, BTN_ENC, 4);
ClickEncoderStream encStream(clickEncoder, 1);

void timerIsr() { clickEncoder.service(); }

// a keyboard with only one key as the encoder button
// keyMap encBtn_map[] = {{-encBtn, defaultNavCodes[enterCmd].ch}}; // negative pin numbers use internal pull-up, on = low
// keyIn<1> encButton(encBtn_map);                                  // 1 is the number of keys

serialIn serial(Serial);

// input from the encoder + encoder button + serial
menuIn *inputsList[] = {&encStream}; // &encStream}; //, &encButton}; //, &serial};
chainStream<1> in(inputsList);       // 3 is the number of inputs

// fontY should now account for fontMarginY
// #define fontX 6
// #define fontY 9
#define MAX_DEPTH 2

// this macro replaces all the above commented lines
#define fontX 6
#define fontY 9
#define offsetX 0
#define offsetY 2
#define U8_Width 128
#define U8_Height 64

MENU_OUTPUTS(out, MAX_DEPTH, U8GLIB_OUT(u8g, colors, fontX, fontY, {0, 0, U8_Width / fontX, U8_Height / fontY}), SERIAL_OUT(Serial));

NAVROOT(nav, mainMenu, MAX_DEPTH, in, out);

result alert(menuOut &o, idleEvent e)
{
  if (e == idling)
  {
    o.setCursor(0, 0);
    o.print("alert test");
    o.setCursor(0, 1);
    o.print("press [select]");
    o.setCursor(0, 2);
    o.print("to continue...");
  }
  return proceed;
}

result doAlert(eventMask e, prompt &item)
{
  nav.idleOn(alert);
  return proceed;
}

// when menu is suspended
result idle(menuOut &o, idleEvent e)
{
  o.clear();
  switch (e)
  {
  case idleStart:
    o.println("suspending menu!");
    break;
  case idling:
    o.println("suspended...");
    break;
  case idleEnd:
    o.println("resuming menu.");
    break;
  }
  return proceed;
}

int lastpos = -1;
void setup()
{
  pinMode(LEDPIN, OUTPUT);

  Serial.begin(250000);
  while (!Serial)
    ;

  Serial.println("<setup()>");

  nav.idleTask = idle; // point a function to be used when menu is suspended
  mainMenu[1].enabled = disabledStatus;

  // change input burst for slow output devices  this is the number of max. processed inputs before drawing
  // nav.inputBurst = 10;

  clickEncoder.setAccelerationEnabled(false);

  pinMode(BTN_EN1, INPUT_PULLUP); // Set BTN_EN1 as an unput, half of the encoder
  digitalWrite(BTN_EN1, HIGH);    // turn on pullup resistors
  pinMode(BTN_EN2, INPUT_PULLUP); // Set BTN_EN2 as an unput, second half of the encoder
  digitalWrite(BTN_EN2, HIGH);    // turn on pullup resistors
  pinMode(BTN_ENC, INPUT_PULLUP); // Set BTN_ENC as an unput, encoder button
  digitalWrite(BTN_ENC, HIGH);    // turn on pullup resistors

  u8g.setFont(u8g_font_helvR08); // Set the font for the display

  pinMode(BTN_ENC, INPUT_PULLUP);
  // encButton.begin();
  // encoder.begin();

  // u8g.setFont(u8g_font_helvR08);
  // u8g.setFont(u8g_font_6x10);
  // u8g.setFont(u8g_font_04b_03r);
  u8g.firstPage();
  do
  {
    u8g.setColorIndex(1);
    nav.out[0].setCursor(0, 0);
    nav.out[0].print(F("Menu 4.x test"));
    nav.out[0].setCursor(0, 1);
    nav.out[0].print(F("on U8Glib"));
  } while (u8g.nextPage());

  Timer1.initialize(1000);
  Timer1.attachInterrupt(timerIsr);
  // delay(2000);

  Serial.println("</setup()>");
}

void loop()
{
  // Serial.println("<loop()>");

  int currval = clickEncoder.getValue();
  if (currval != lastpos)
  {
    Serial.println(currval);
    lastpos = currval;
  }

  // nav.poll();

  nav.doInput();

  if (nav.changed(0))
  {
    // only draw if menu changed for gfx device
    // because this code clears the screen, if always called then screen will blink
    u8g.firstPage();
    do
      nav.doOutput();
    while (u8g.nextPage());
  }
  digitalWrite(LED_BUILTIN, ledCtrl);

  // delay(100); // simulate other tasks delay

  //  Serial.println("</loop()>");
}