Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

menu buttons #161

Closed
AlexFundorin opened this issue Jan 16, 2017 · 26 comments
Closed

menu buttons #161

AlexFundorin opened this issue Jan 16, 2017 · 26 comments
Labels

Comments

@AlexFundorin
Copy link

I'm using psp analog stick and capacitive touch pads in my device.
A separate function is used to read pad's state, which is stored in pad[i] array. I've tried to point to pad[0], pad[1] and so on in the "begin" section for menu buttons, without any luck.
Is there any way to use variables as menu triggers in thу library?

@olikraus
Copy link
Owner

Same as #152 and #150 --> No extension here.
U8g2 is a graphics lib, not a generic user menu lib.
The existing button functions are just there as an example.
Hope this is ok for you.

@AlexFundorin
Copy link
Author

Thanks. What about your m2tk library? Do you have any plans to update it?
I'm currently choosing a way to implement menu system, that would work with u8g2.

@olikraus
Copy link
Owner

well, yes, m2tk... plan is there, time is missing :-(

U8g2 and M2tk are both very time consuming. At the moment i concentrate on U8g2 only.

@Giuse1977
Copy link

Ciao Oliver
I fully agree with you when you say that this library focus is driving monochrome displays, but I think would be nice to add all least some kind of handler where to hook with the user input device.
It's days I'm struggling to find where to intercept a call or how to modify debounce.c and selection_list.c and still I've found no way to use my thumbstick (actually it works when one of its axis returns a LOW value, but this is not the point).
I found your user selection list function useful, and will fit nicely in lots of project of users like me, that are "advance beginner" with arduino, but completely noobs in C (so unable to modify and often read c files) .
Sorry for reopening issue, I hope you understand my frustration, and can at least point me in the right direction : )
Giuseppe

@AlexFundorin
Copy link
Author

I'm also trying to find a way to alter setting of my device, using a thumbstick and think that the example menu suits my needs, except there's no way to assign other controls than pushbutton with it.

@olikraus
Copy link
Owner

Giuseppe, you can of course reopen the issue...

You can just remove u8x8_debounce.c and write your own "u8x8_GetMenuEvent" procedure.
Thats all. But of course i can not help you to support your thumbstick .
For this, you need to find some example code somewhere else.

uint8_t u8x8_GetMenuEvent(u8x8_t *u8x8)
{
int c;
c = getc(stdin);
switch(c)
{
case 'n':
return U8X8_MSG_GPIO_MENU_NEXT;
case 'p':
return U8X8_MSG_GPIO_MENU_PREV;
case 's':
return U8X8_MSG_GPIO_MENU_SELECT;
case 'h':
return U8X8_MSG_GPIO_MENU_HOME;
case 'x':
exit(0);
default:
break;
}
return 0;
}

@Giuse1977
Copy link

Ciao Oliver
It took me a couple of hours to find out which file was to edit, but is way too difficult for my knowledge to modify it at the moment.
Thank you for answering!
@AlexFundorin can we try together?

@AlexFundorin
Copy link
Author

Yes, we can. I kinda understand what should be done.
Write me on telegram and we'll try to figure out something - fundorin.

As far as I understand, we should make variable "c" equal one of the following letters: n, p, s, h, x (as given in example) in our own code, depending on the thumbstick direction.
I also think that it might be possible to add a copy of u8x8_debounce.c into the sketch folder, so there would be no need to delete the original file from the library.

@olikraus olikraus reopened this Jan 31, 2017
@olikraus
Copy link
Owner

olikraus commented Jan 31, 2017

As far as I understand, we should make variable "c" equal one of the following letters: n, p, s, h, x (as given in example) in our own code, depending on the thumbstick direction.

this is only an example for a linux system. It is just important that the function returns these constants like U8X8_MSG_GPIO_MENU_NEXT or U8X8_MSG_GPIO_MENU_PREV.

It should be like this;

uint8_t u8x8_GetMenuEvent(u8x8_t *u8x8)
{
  If ( thumbstick is pushed to the left )
    return U8X8_MSG_GPIO_MENU_PREV;
  If ( thumbstick is pushed to the right )
    return U8X8_MSG_GPIO_MENU_NEXT;
 ...
}

So you job is only to detect the movement direction of the thumbstick (or any other device)

All in all there are six events predefined:
U8X8_PIN_MENU_SELECT
U8X8_PIN_MENU_NEXT
U8X8_PIN_MENU_PREV
U8X8_PIN_MENU_HOME
U8X8_PIN_MENU_UP
U8X8_PIN_MENU_DOWN

Oliver

@AlexFundorin
Copy link
Author

AlexFundorin commented Jan 31, 2017

This is my function:
uint8_t u8x8_GetMenuEvent(u8x8_t *u8x8) { if (pad[10]) { return U8X8_MSG_GPIO_MENU_SELECT; } if (joyR > 100) { return U8X8_MSG_GPIO_MENU_NEXT; } if (joyL > 100) { return U8X8_MSG_GPIO_MENU_PREV; } if (pad[8]) { return U8X8_MSG_GPIO_MENU_HOME; } if (joyU > 100) { return U8X8_MSG_GPIO_MENU_UP; } if (joyD > 100) { return U8X8_MSG_GPIO_MENU_DOWN; } }
(added a screenshot cause the formatting of the code is weird - http://i.imgur.com/oTFFKqZ.png)

I've renamed debounce .c file and added the above function to my code. At compiling I get this notice:
`routines: In function 'uint8_t u8x8_GetMenuEvent(u8x8_t*)':
routines:58: warning: control reaches end of non-void function
}

^`
Don't know what it means. I guess that the function should return to variables, but what is the second one?

Should I use U8X8_PIN_MENU_PREV or U8X8_MSG_GPIO_MENU_PREV inside .ino sketch?

@AlexFundorin
Copy link
Author

AlexFundorin commented Jan 31, 2017

Added "else { return 0; }" and the notice is gone.

Now I need to find a way of how to call that u8x8_GetMenuEvent(u8x8_t *u8x8) function and what arguments should I pass to it.

By now, I'm having this error: http://i.imgur.com/4cZpXG5.png
It's because I call this function as 'u8x8_GetMenuEvent(joyD);' where joyD is, obviously, an integer.

@olikraus
Copy link
Owner

olikraus commented Jan 31, 2017

It's because I call this function as 'u8x8_GetMenuEvent(joyD);' where joyD is, obviously, an integer.

Of course you should call this function with &u8x8 object (or u8g2.GetU8x8(), u8x8.GetU8x8()). joyD should be a global variable instead.

One more point: You should not only check for "joyD>100". This will obviously fire a lot of events whenever this condition is true. Instead you may want to stop returning events and wait until joyD becomes <= 100. Only after joyD is > 100 again, the next event will be sent.
Of course something like autorepeat is thinkable. But this would require some delay (but without calling the delay function of course).

As i said, this is not so easy and not scope of u8g2...

... i personally suggest to draw a state diagramm first (https://en.wikipedia.org/wiki/State_diagram)...

@AlexFundorin
Copy link
Author

Thanks, Oli. I'll deal with repeats later. That's not a problem at all.
The main issue now is to call this function properly.
Is there a way to replace &u8x8 (yet I knew what it is :)) with int?
I've tried calling it without any arguments, but it didn't work. I wonder what is the proper way of calling this function, so that I could use it as I want.

P.S. I'm still thinking about m2tk. Is it compatible with u8g2 library?

@Giuse1977
Copy link

Guys,
from my side I can only share how I got a realiable way to read joystick input in a sketch, or suggest to simply change the way navigation buttons are read: each axys is HIGH in one direction and LOW in the opposite, so we could track 2 inputs for each pin (left/right-up/down) and we should implement a way to detect a long press (for home) from a short one (select). This way we should get the 6 "buttons" we are looking for. This would be a non scalable solution, but it can work.

This is the way I manage the joystick

``
void Switch () { if (digitalRead(7) == LOW) {sw=true; myMenu ();} }//may be better with interrupts..next version update

void myMenu () {
delay (500); //delay to relase button
Menu();
wait=timeout;
do { //wait for input until timeout expires
wait--;
delay (100);
}while (joyRead()==0&&wait!=0) ;
wait=timeout;
if (joyRead() !=0) { //if input given read it

 do {                               
    
      switch (joyRead()){
        case 5:
          sw=!sw;
          break;
        case 1: //left
          while (joyRead()!=0&&wait!=0){
          wait=timeout; 
          wait--;
          delay (100);
          }
          wait=timeout;
          page--;
          if (page>4)page=4; //after page 0 return to 4
          break;
      case 3: //right
          while (joyRead()!=0&&wait!=0){
          wait=timeout; 
          wait--;
          delay (100);
          }
          wait=timeout;
          page++;
          if (page>4)page=0; //after page 4 return to home
          break;
    }
  wait--;
  delay (100);
  }while (sw&&wait!=0); //until switch pressed or timeout reached

byte joyRead() {
if (digitalRead(7) == LOW) return 5; //read button first
else { //if no button press continue
int xPos = analogRead(A2); //read x Axys
int yPos = analogRead(A3); //read y Axys
xPos=xPos+42; //set joystick offset
xPos= map (xPos,0,1021,-1,1); //map x Axys to -1/+1
yPos= map (yPos,0,1021,-1,1); //map y Axys to -1/+1
int absPos = (xPos+xPos) - yPos; //double xPos to show unique values for each joystick position

  switch (absPos){
    case 1: //left
      return 1;
       break;
    case -2:
      return 2;//up
      break;
    case -1:
      return 3;//right
        break;
    case 2:
      return 4;//down
        break;
    default:
      return 0;
        break;
    }
 }

}``

@olikraus
Copy link
Owner

Is there a way to replace &u8x8 (yet I knew what it is :)) with int?

Basically you can also pass "NULL", because your replacement does not use the u8x8 structure. However if you call one of the u8x8-user function, u8x8 will automatically be passed. But since you do not use this, you can just ignore this. So finally: Just pass NULL and do not worry about the argument.

I've tried calling it without any arguments, but it didn't work. I wonder what is the proper way of calling this function, so that I could use it as I want.

hmm, but you did not use NULL, right?

P.S. I'm still thinking about m2tk. Is it compatible with u8g2 library?

I am working on this, but progress is very slow...

@Giuse1977
Copy link

I've tried to modify debounce.c this way (tnx Alex):

uint8_t u8x8_GetMenuEvent(u8x8_t *u8x8)
{
if (digitalRead(U8X8_PIN_MENU_SELECT) == LOW) { return U8X8_MSG_GPIO_MENU_SELECT; }
if (analogRead (U8X8_PIN_MENU_DOWN)==LOW) { return U8X8_MSG_GPIO_MENU_NEXT; }
if (analogRead (U8X8_PIN_MENU_DOWN)==HIGH) { return U8X8_MSG_GPIO_MENU_PREV; }
if (analogRead (U8X8_PIN_MENU_UP)==HIGH) { return U8X8_MSG_GPIO_MENU_UP; }
if (analogRead (U8X8_PIN_MENU_UP)==HIGH) { return U8X8_MSG_GPIO_MENU_DOWN; } }
else { return NULL; }
}

Saving the modified file to src folder doesn't sort any effect..I can still browse up/down the same way as before (left scrolls down, up scrolls up because in those directions pins are drived low)..

@olikraus
Copy link
Owner

Sometimes you have to restart the IDE to force a full rebuild.

@olikraus olikraus closed this as completed Feb 5, 2017
@Giuse1977
Copy link

Thanks for support, I finally gave up.

Regards

Giuseppe

@Jorgen-VikingGod
Copy link

I'm looking for similar solution. I have a rotary encoder and want to navigate through menu list.
Would it be not better to have some overloaded stuff, to get correct menu command (left, right, select, ...) by user.
Otherwise some methods like xyz.menuLeft(), xyz.menuSelect(), ... would be great
So everyone who is not using buttons on GPIOs can call these methods after fetching his direction logic.

@olikraus
Copy link
Owner

I have always considered the menu functions as a simple add on. A menu system, which supports rotary encoder, buttons at digital or analog input or even remote controllers, should be extra lib.

@tomivm
Copy link

tomivm commented Nov 14, 2017

Hello, I modified u8x8_debounce.c and it works fine!, In my case I dont have more pins for the buttons and I use 3 buttons with a combination of resistor on the analog port, if you like,let tale me know!
I'm trying to add a timer, when I get it, I'll upload it. Anyway it works well . =)

<#include

"u8x8.h"

/*
State A:
u8x8->debounce_last_pin_state == current_state
--> State A
u8x8->debounce_last_pin_state != current_state
--> u8x8->debounce_last_pin_state = current_state
--> State B + cnt

State B + cnt
--> state--

State B
u8x8->debounce_last_pin_state == current_state
--> keypress detected
--> State C
u8x8->debounce_last_pin_state != current_state
--> State A

State C
u8x8->debounce_last_pin_state == current_state
--> State C
u8x8->debounce_last_pin_state != current_state
--> State A

*/
char test_buttons(void)//(int *testear_boton)
{
// revisar_timer();
// if (*testear_boton == 1)
// {
int dataan = analogRead(0);
// Serial.println("dato an:");
// Serial.println(datoan);
if (dataan > 20)
{
if (dataan > 650 && dataan < 1024)//izquierda
{

      //         void U8G2::clearDisplay(void)  ; u8g2.clearBuffer();
      //         u8g2.drawStr("DERECHA",1,1);
        return 'p';
    }
    else if (dataan > 300 && dataan < 650)//enter
    {
      //          void U8G2::clearDisplay(void)  ; u8g2.clearBuffer();
      //          u8g2.drawStr("Enter",1,1);
     return 's';
    }
    else if (dataan > 150 && dataan < 300)  //derecha
    {

      //              void U8G2::clearDisplay(void)  ; u8g2.clearBuffer();
      //              u8g2.drawStr("Enter",1,1);
      return 'n';
    }
  }
  else
  {
     return 'z';
  }

// *testear_boton = 0;
// }
}

#ifdef __unix__xxxxxx_THIS_IS_DISABLED

#include <stdio.h>
#include <stdlib.h>
uint8_t u8x8_GetMenuEvent(void)
{
yield();
int c;
c = test_buttons();//getc(stdin);
switch(c)
{
case 'n':
return U8X8_MSG_GPIO_MENU_NEXT;
case 'p':
return U8X8_MSG_GPIO_MENU_PREV;
case 's':
return U8X8_MSG_GPIO_MENU_SELECT;
case 'h':
return U8X8_MSG_GPIO_MENU_HOME;
case 'x':
// exit(0);
default:
puts("press n, p, s, h or x");
break;
}
return 0;
}

#else /* unix */

#define U8X8_DEBOUNCE_WAIT 2
/* do debounce and return a GPIO msg which indicates the event /
/
returns 0, if there is no event */
#ifdef GNUC

pragma weak u8x8_GetMenuEvent

#endif
uint8_t u8x8_GetMenuEvent(u8x8_t *u8x8)
{
yield();
int c;
c = test_buttons();//getc(stdin);
switch(c)
{
case 'n':
return U8X8_MSG_GPIO_MENU_NEXT;
case 'p':
return U8X8_MSG_GPIO_MENU_PREV;
case 's':
return U8X8_MSG_GPIO_MENU_SELECT;
case 'h':
return U8X8_MSG_GPIO_MENU_HOME;
case 'x':
// exit(0);
default:
puts("press n, p, s, h or x");
break;
}
return 0;
}

#endif /* unix */>
sorry @olikraus if this is not the correct way!

@Triscus
Copy link

Triscus commented Dec 18, 2017

I have a library and an object for my rotary encoder. But I am not able to use the object in the GetMenuEvent() function. I tried to follow olis suggestion:

It is just important that the function returns these constants like U8X8_MSG_GPIO_MENU_NEXT or U8X8_MSG_GPIO_MENU_PREV.

...

So you job is only to detect the movement direction of the thumbstick (or any other device)

and

You can just remove u8x8_debounce.c and write your own "u8x8_GetMenuEvent" procedure.

I edited the debounce.c to something like this:

#include "MyRotaryLibrary.h"

uint8_t u8x8_GetMenuEvent(u8x8_t *u8x8,class MyRotary fancyknob)

{
	if (fancyknob.positionDelta()==1 ) //rotary turn left

	{		
			return U8X8_MSG_GPIO_MENU_UP;

	}
	if (fancyknob.positionDelta() == -1)  //rotary turn right

	{
			return U8X8_MSG_GPIO_MENU_DOWN;
			
	}
}

I also tried renaming the debounce.c to a .cpp file, but this breaks the other menu functions:

u8g2_input_value.c.o*: In function u8g2_UserInterfaceInputValue
u8g2_input_value.c:119: undefined reference to u8x8_GetMenuEvent
 
u8g2_selection_list.c.o*: In function u8g2_UserInterfaceSelectionList
u8g2_selection_list.c:267: undefined reference to u8x8_GetMenuEvent

removing debounce.c and defining the function in the .ino and wrapping it with

 extern "C"
 {
 
 }

isn't working either. The compiler complains about not definied functions.

I am a bit lost dealing with the .c files so any advice would be highly appreciated

Kind Regards

Triscus

@olikraus
Copy link
Owner

hmmm redefinition and declaration as extern "C" should work...

@Triscus
Copy link

Triscus commented Dec 19, 2017

so the definition can be done in an .ino file?

@olikraus
Copy link
Owner

yes, i think so. But Arduino IDE may do some extra modification, which i do not know.

@Triscus
Copy link

Triscus commented Jan 23, 2018

@tomivm already had the solution in his reply, but I wasn't able to adapt it.

Declaring the function in the u8x8_debounce.c as weak and redefine it in the ino (without extern "C") seems to work now:

Editing u8x8_debcounce.c:

#pragma weak u8x8_GetMenuEvent

uint8_t u8x8_GetMenuEvent(u8x8_t *u8x8)
{
...    //nothing was change here
}

Function in .ino (where knob is the object for the rotary ):

uint8_t u8x8_GetMenuEvent(u8x8_t *u8x8)
{
	knob.update();
	int turn = knob.positionDelta();

	switch (turn)
	{
	case 1:
		return U8X8_MSG_GPIO_MENU_UP;
	case -1:
		return U8X8_MSG_GPIO_MENU_DOWN;
	default:
		break;
	}

	Serial.println(turn);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants