rockbox/firmware/drivers/button_queue.c
Hairo R. Carela 48392bab94 New port: Anbernic RG Nano
A bit of context, this device is a clone of the FunKey-S with a different form factor, hardware is mostly identical, the relevant difference is it has audio out (via usb-c, adapter to 3.5mm is included), this is the reason why the FunKey-SDK is needed for bulding.

This port is based on the old SDL 1.2 code because the device doesn't have SDL2 support. Alongside what was supported in the SDL 1.2 builds this port supports battery level, charging status and backlight control.

Change-Id: I7fcb85be62748644b667c0efebabf59d6e9c5ade
2025-07-29 21:01:53 -04:00

230 lines
5.9 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Daniel Stenberg
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include "system.h"
#include "kernel.h"
#include "button.h"
#ifdef HAVE_SDL
#include "SDL.h"
#if SDL_MAJOR_VERSION > 1
#include "window-sdl.h"
#endif
#endif
static struct event_queue button_queue SHAREDBSS_ATTR;
static intptr_t button_data; /* data value from last message dequeued */
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
static bool button_boosted = false;
static long button_unboost_tick;
#define BUTTON_UNBOOST_TMO HZ
static void button_boost(bool state)
{
if (state)
{
/* update the unboost time each button_boost(true) call */
button_unboost_tick = current_tick + BUTTON_UNBOOST_TMO;
if (!button_boosted)
{
button_boosted = true;
cpu_boost(true);
}
}
else if (button_boosted && TIME_AFTER(current_tick, button_unboost_tick))
{
button_boosted = false;
cpu_boost(false);
}
}
static void button_queue_wait(struct queue_event *evp, int timeout)
{
/* Loop once after wait time if boosted in order to unboost and wait the
full remaining time */
do
{
int ticks = timeout;
if (ticks == TIMEOUT_NOBLOCK)
;
else if (ticks > 0)
{
if (button_boosted && ticks > BUTTON_UNBOOST_TMO)
ticks = BUTTON_UNBOOST_TMO;
timeout -= ticks;
}
else if (button_boosted) /* TIMEOUT_BLOCK (ticks < 0) */
{
ticks = BUTTON_UNBOOST_TMO;
}
queue_wait_w_tmo(&button_queue, evp, ticks);
if (evp->id != SYS_TIMEOUT)
{
/* GUI boost build gets immediate kick, otherwise at least 3
messages had to be there */
#ifndef HAVE_GUI_BOOST
if (queue_count(&button_queue) >= 2)
#endif
button_boost(true);
break;
}
button_boost(false);
}
while (timeout);
}
#else /* ndef HAVE_ADJUSTABLE_CPU_FREQ */
static inline void button_queue_wait(struct queue_event *evp, int timeout)
{
#if defined(__APPLE__) && (CONFIG_PLATFORM & PLATFORM_SDL)
unsigned long initial_tick = current_tick;
unsigned long curr_tick, remaining;
while(true)
{
SDL_PumpEvents();
queue_wait_w_tmo(&button_queue, evp, TIMEOUT_NOBLOCK);
if (evp->id != SYS_TIMEOUT || timeout == TIMEOUT_NOBLOCK)
return;
else if (timeout == TIMEOUT_BLOCK)
sleep(HZ/60);
else
{
curr_tick = current_tick;
if (!TIME_AFTER(initial_tick + timeout, curr_tick))
return;
remaining = ((initial_tick + timeout) - curr_tick);
sleep(remaining < HZ/60 ? remaining : HZ/60);
}
}
#else
queue_wait_w_tmo(&button_queue, evp, timeout);
#if defined(HAVE_SDL) && (SDL_MAJOR_VERSION > 1)
sdl_window_adjust(); /* Window may have been resized */
#endif
#endif
}
#endif /* HAVE_ADJUSTABLE_CPU_FREQ */
void button_queue_post(long id, intptr_t data)
{
queue_post(&button_queue, id, data);
}
void button_queue_post_remove_head(long id, intptr_t data)
{
queue_remove_from_head(&button_queue, id);
queue_post(&button_queue, id, data);
}
bool button_queue_try_post(long button, int data)
{
#ifdef HAVE_TOUCHSCREEN
/* one can swipe over the scren very quickly,
* for this to work we want to forget about old presses and
* only respect the very latest ones */
const bool force_post = true;
#else
/* Only post events if the queue is empty,
* to avoid afterscroll effects.
* i.e. don't post new buttons if previous ones haven't been
* processed yet - but always post releases */
const bool force_post = button & BUTTON_REL;
#endif
if (!queue_empty(&button_queue))
{
if (force_post)
queue_remove_from_head(&button_queue, button);
else
return false;
}
queue_post(&button_queue, button, data);
/* on touchscreen we posted unconditionally */
return true;
}
int button_queue_count(void)
{
return queue_count(&button_queue);
}
bool button_queue_empty(void)
{
return queue_empty(&button_queue);
}
bool button_queue_full(void)
{
return queue_full(&button_queue);
}
void button_clear_queue(void)
{
queue_clear(&button_queue);
}
/* clears anything but release and sysevents */
void button_clear_pressed(void)
{
long button;
for (int count = queue_count(&button_queue); count > 0; count--)
{
button = button_get(false);
if (button & (BUTTON_REL | SYS_EVENT))
{
button_queue_post(button, button_data);
}
}
}
long button_get_w_tmo(int ticks)
{
struct queue_event ev;
button_queue_wait(&ev, ticks);
if (ev.id == SYS_TIMEOUT)
ev.id = BUTTON_NONE;
else
button_data = ev.data;
return ev.id;
}
long button_get(bool block)
{
return button_get_w_tmo(block ? TIMEOUT_BLOCK : TIMEOUT_NOBLOCK);
}
intptr_t button_get_data(void)
{
return button_data;
}
void INIT_ATTR button_queue_init(void)
{
queue_init(&button_queue, true);
}