ugfx/src/ginput/ginput_dial.c

154 lines
3.8 KiB
C

/*
* This file is subject to the terms of the GFX License. If a copy of
* the license was not distributed with this file, you can obtain one at:
*
* http://ugfx.io/license.html
*/
/**
* @file src/ginput/ginput_dial.c
* @brief GINPUT dial code.
*
* @defgroup Dial Dial
* @ingroup GINPUT
* @{
*/
#include "../../gfx.h"
#if GFX_USE_GINPUT && GINPUT_NEED_DIAL
#include "ginput_driver_dial.h"
static GTIMER_DECL(DialTimer);
static struct DialStatus_t {
gU16 sensitivity;
gU16 lastvalue;
gU16 max;
} DialStatus[GINPUT_DIAL_NUM_PORTS];
// The reading callback function
static void DialCallback(gU16 instance, gU16 rawvalue) {
struct DialStatus_t *pds;
GSourceListener *psl;
GEventDial *pe;
/* Get the information we need */
pds = DialStatus+instance;
/* Range scale - if needed */
if (pds->max != GINPUT_DIAL_MAX_VALUE)
rawvalue = (gU16)((gU32)rawvalue * pds->max / GINPUT_DIAL_MAX_VALUE);
/* Forget about changes below our sensitivity threshold */
if (rawvalue >= pds->lastvalue) {
if (rawvalue - pds->lastvalue < pds->sensitivity) return;
} else {
if (pds->lastvalue - rawvalue < pds->sensitivity) return;
}
/* Save the value */
pds->lastvalue = rawvalue;
// Send the event to the listeners that are interested.
psl = 0;
while ((psl = geventGetSourceListener((GSourceHandle)(DialStatus+instance), psl))) {
if (!(pe = (GEventDial *)geventGetEventBuffer(psl)))
continue;
pe->type = GEVENT_DIAL;
pe->instance = instance;
pe->value = pds->lastvalue;
pe->maxvalue = pds->max;
geventSendEvent(psl);
}
}
GSourceHandle ginputGetDial(gU16 instance) {
struct DialStatus_t *pds;
if (instance >= GINPUT_DIAL_NUM_PORTS)
return 0;
// Do we need to initialise the dial subsystem?
if (!gtimerIsActive(&DialTimer)) {
for(pds = DialStatus; pds < DialStatus+GINPUT_DIAL_NUM_PORTS; pds++) {
pds->max = GINPUT_DIAL_MAX_VALUE;
#if GINPUT_DIAL_MAX_VALUE < 100
pds->sensitivity = 1;
#else
pds->sensitivity = GINPUT_DIAL_MAX_VALUE/100;
#endif
pds->lastvalue = 0;
}
ginput_lld_dial_init();
gtimerStart(&DialTimer, (GTimerFunction)ginput_lld_dial_poll, DialCallback, gTrue, GINPUT_DIAL_POLL_PERIOD);
}
// OK - return this input
return (GSourceHandle)(DialStatus+instance);
}
void ginputResetDialRange(gU16 instance) {
if (instance >= GINPUT_DIAL_NUM_PORTS)
return;
ginputSetDialRange(instance, GINPUT_DIAL_MAX_VALUE);
}
gU16 ginputGetDialRange(gU16 instance) {
if (instance >= GINPUT_DIAL_NUM_PORTS)
return 0;
return DialStatus[instance].max;
}
void ginputSetDialRange(gU16 instance, gU16 max) {
struct DialStatus_t *pds;
if (instance >= GINPUT_DIAL_NUM_PORTS)
return;
pds = DialStatus+instance;
// Rescale the last value and the sensitivity
if (max != pds->max) {
pds->lastvalue = (gU16)((gU32)pds->lastvalue * max / pds->max);
pds->sensitivity = (gU16)((gU32)pds->sensitivity * max / pds->max);
pds->max = max;
}
}
/**
* @brief Set the level change required before a dial even is generated (threshold)
* @note This is done after range scaling
*
* @param[in] instance The ID of the dial input instance
* @param[in] diff The amount of level changes
*/
void ginputSetDialSensitivity(gU16 instance, gU16 diff) {
if (instance >= GINPUT_DIAL_NUM_PORTS)
return;
DialStatus[instance].sensitivity = diff;
}
/**
* @brief Get the current dial status
*
* @param[in] instance The ID of the dial input instance
* @param[in] pdial The dial event struct
*
* @return Returns gFalse on an error (eg invalid instance)
*/
gBool ginputGetDialStatus(gU16 instance, GEventDial *pdial) {
if (instance >= GINPUT_DIAL_NUM_PORTS)
return gFalse;
pdial->type = GEVENT_DIAL;
pdial->instance = instance;
pdial->value = DialStatus[instance].lastvalue;
pdial->maxvalue = DialStatus[instance].max;
return gTrue;
}
#endif /* GFX_USE_GINPUT && GINPUT_NEED_DIAL */
/** @} */