Hi Tomek,

I think the Single Button Actions will be a good name (maybe in future it
could have a dual click function, like used in mouses).

Yes, the idea is to use some generic system timer to get it working on all
MCUs.

BR,

Alan

On Wed, Jul 9, 2025 at 11:03 AM Tomek CEDRO <to...@cedro.info> wrote:

> Hey there Alan :-)
>
> Very cool and useful idea! I did something like this long time ago in
> pure assembly and C but it was returning press time and based on that
> actions were performed by the handling routine.
>
> In NuttX this would work on various platforms where different
> capabilities (i.e. irq, timers, etc) may be used for hardware
> acceleration, but I think generic approach based on system timer that
> would work on everything could be the first step :-)
>
> Good self-explanatory name for such module would be nice to have, what
> do you think about "Single Button Actions" or similar? Singe Button
> tells only one button is used to perform various Actions.
>
> Thanks :-)
> Tomek
>
>
> On Wed, Jul 9, 2025 at 3:17 PM Alan C. Assis <acas...@gmail.com> wrote:
> >
> > Hi Everyone,
> >
> > Some years ago a customer asked me to develop a project with NuttX for
> this
> > board that used a small OLED display and a single button.
> > That button should be used to navigate in the menu, as a side note:
> > initially he suggested: quick press and release will work as a ENTER and
> > long press will work as TAB (move to other option),
> > but while testing the application I released the was faster if quick
> press
> > work as TAB and long press as enter.
> >
> > This video implements the same idea on a ESP32-Devkit board that also has
> > only a single button: https://www.youtube.com/shorts/vfQLW-a2JhA
> >
> > The daemon that detect the button and define the type of input is
> something
> > like this:
> >
> >   /* Define the notifications events */
> >
> >   btnevents.bn_press   = supported;
> >   btnevents.bn_release = supported;
> >
> >   btnevents.bn_event.sigev_notify = SIGEV_SIGNAL;
> >   btnevents.bn_event.sigev_signo  = CONFIG_INPUT_BUTTONS_SIGNO;
> >
> >   /* Register to receive a signal when buttons are pressed/released */
> >
> >   ret = ioctl(fd, BTNIOC_REGISTER,
> >               (unsigned long)((uintptr_t)&btnevents));
> >   if (ret < 0)
> >     {
> >       int errcode = errno;
> >       printf("button_daemon: ERROR: ioctl(BTNIOC_SUPPORTED) failed:
> %d\n",
> >              errcode);
> >       goto errout_with_fd;
> >     }
> >
> >   /* Ignore the default signal action */
> >
> >   signal(CONFIG_INPUT_BUTTONS_SIGNO, SIG_IGN);
> >
> >   /* Now loop forever, waiting BUTTONs events */
> >
> >   for (; ; )
> >     {
> >       struct siginfo value;
> >       sigset_t set;
> >
> >       bool timeout;
> >       int nbytes;
> >
> >       /* Wait for a signal */
> >
> >       sigemptyset(&set);
> >       sigaddset(&set, CONFIG_INPUT_BUTTONS_SIGNO);
> >       ret = sigwaitinfo(&set, &value);
> >       if (ret < 0)
> >         {
> >           int errcode = errno;
> >           printf("ERROR: sigwaitinfo() failed: %d\n", errcode);
> >           goto errout_with_fd;
> >         }
> >
> >       sample = (btn_buttonset_t)value.si_value.sival_int;
> >
> >       if (sample & 0x01)
> >         {
> >           /* Button pressed, start measuring time */
> >
> >           clock_gettime(CLOCK_REALTIME, &start);
> >         }
> >       else
> >         {
> >           /* Button released, calculate the elapsed time */
> >
> >           clock_gettime(CLOCK_REALTIME, &curr);
> >
> >           elapsed.tv_sec  = curr.tv_sec - start.tv_sec;
> >           if (curr.tv_nsec >= start.tv_nsec)
> >             {
> >               elapsed.tv_nsec = curr.tv_nsec - start.tv_nsec;
> >             }
> >           else
> >             {
> >               unsigned long borrow = 1000000000 - start.tv_nsec;
> >               elapsed.tv_sec--;
> >               elapsed.tv_nsec = curr.tv_nsec + borrow;
> >             }
> >
> >  unsigned long ftime = (elapsed.tv_sec * 1000000000) + elapsed.tv_nsec;
> >
> >  /*printf("Elapsed miliseconds = %d\n", ftime / 1000000);*/
> >  if (ftime < 500000000)
> >             {
> >               input_event(INPUT_TAB);
> >             }
> >  else
> >             {
> >               input_event(INPUT_ENTER);
> >             }
> >         }
> >
> >       /* Make sure that everything is displayed */
> >
> >       fflush(stdout);
> >
> >       usleep(1000);
> >     }
> >
> > But today while taking a shower and thinking about other subjects that
> fact
> > came to mind and I asked myself: how to develop that thing in a more
> > standard way to avoid the "kludge" above? (in fact it is not kludge, but
> we
> > can improve, right?)
> >
> > So, I realized it would be nice to have a kind of "action button" driver
> > that generates this kind of event (detecting long press and short press)
> > automatically returning INPUT_ENTER or INPUT_TAB.
> >
> > In fact the driver will be more similar to djoystick.c than the ordinary
> > buttons driver itself (for simplicity).
> >
> > Please let me know if someone already implemented something similar or
> > other suggestions before I implement it.
> >
> > BR,
> >
> > Alan
>
>
>
> --
> CeDeROM, SQ7MHZ, http://www.tomek.cedro.info
>

Reply via email to