mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-16 00:00:07 +01:00
168 lines
4.8 KiB
C
168 lines
4.8 KiB
C
/*
|
|
* Generic GPIO / irq buttons
|
|
*
|
|
* Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to
|
|
* deal in the Software without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
* IN THE SOFTWARE.
|
|
*/
|
|
#include "private-lib-core.h"
|
|
|
|
#if defined(LWS_PLAT_FREERTOS)
|
|
#include <freertos/timers.h>
|
|
#endif
|
|
|
|
/*
|
|
* This is the opaque, allocated, non-const, dynamic footprint of the
|
|
* button controller
|
|
*/
|
|
|
|
typedef struct lws_button_state {
|
|
#if defined(LWS_PLAT_FREERTOS)
|
|
TimerHandle_t timer;
|
|
#endif
|
|
const lws_button_controller_t *controller;
|
|
struct lws_context *ctx;
|
|
lws_button_idx_t enable_bitmap;
|
|
lws_button_idx_t state_bitmap;
|
|
} lws_button_state_t;
|
|
|
|
/*
|
|
* This is the bottom-half scheduled via a timer set in the ISR. From here
|
|
* we are allowed to hold mutexes etc. We are coming here because any button
|
|
* interrupt arrived, we have to try to figure out which events have happened.
|
|
*/
|
|
|
|
#if defined(LWS_PLAT_FREERTOS)
|
|
static void
|
|
lws_button_bh(TimerHandle_t th)
|
|
{
|
|
lws_button_state_t *bcs = pvTimerGetTimerID(th);
|
|
|
|
lws_smd_msg_printf(bcs->ctx, LWSSMDCL_INTERACTION,
|
|
"{\"btn\":\"%s/%s\", \"s\":\"click\"}",
|
|
bcs->controller->smd_bc_name,
|
|
bcs->controller->button_map[0].smd_interaction_name);
|
|
|
|
#if 0
|
|
if (lws_esp32.button_is_down)
|
|
gpio_set_intr_type(GPIO_SW, GPIO_INTR_POSEDGE);
|
|
else
|
|
gpio_set_intr_type(GPIO_SW, GPIO_INTR_NEGEDGE);
|
|
|
|
lws_esp32.button_is_down = gpio_get_level(GPIO_SW);
|
|
|
|
lws_esp32_button(lws_esp32.button_is_down);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
struct lws_button_state *
|
|
lws_button_controller_create(struct lws_context *ctx,
|
|
const lws_button_controller_t *controller)
|
|
{
|
|
lws_button_state_t *bcs = lws_zalloc(sizeof(lws_button_state_t), __func__);
|
|
|
|
if (!bcs)
|
|
return NULL;
|
|
|
|
bcs->controller = controller;
|
|
bcs->ctx = ctx;
|
|
|
|
#if defined(LWS_PLAT_FREERTOS)
|
|
bcs->timer = xTimerCreate("bcst", 1, 0, bcs,
|
|
(TimerCallbackFunction_t)lws_button_bh);
|
|
#endif
|
|
|
|
return bcs;
|
|
}
|
|
|
|
void
|
|
lws_button_controller_destroy(struct lws_button_state *bcs)
|
|
{
|
|
/* disable them all */
|
|
lws_button_enable(bcs, 0, 0);
|
|
|
|
#if defined(LWS_PLAT_FREERTOS)
|
|
xTimerDelete(&bcs->timer, 0);
|
|
#endif
|
|
|
|
lws_free(bcs);
|
|
}
|
|
|
|
/*
|
|
* This is happening in interrupt context, we have to schedule a bottom half to
|
|
* do the foreground lws_smd queueing, using, eg, a platform timer.
|
|
*
|
|
* All the buttons point here and use one timer per button controller. An
|
|
* interrupt here means, "something happened to one or more buttons"
|
|
*/
|
|
|
|
void
|
|
lws_button_irq_cb_t(void *arg)
|
|
{
|
|
#if defined(LWS_PLAT_FREERTOS)
|
|
lws_button_state_t *bcs = (lws_button_state_t *)arg;
|
|
|
|
xTimerStart(bcs->timer, 0);
|
|
#endif
|
|
}
|
|
|
|
lws_button_idx_t
|
|
lws_button_get_bit(struct lws_button_state *bcs, const char *name)
|
|
{
|
|
const lws_button_controller_t *bc = bcs->controller;
|
|
int n;
|
|
|
|
for (n = 0; n < bc->count_buttons; n++)
|
|
if (!strcmp(name, bc->button_map[n].smd_interaction_name))
|
|
return 1 << n;
|
|
|
|
return 0; /* not found */
|
|
}
|
|
|
|
void
|
|
lws_button_enable(lws_button_state_t *bcs,
|
|
lws_button_idx_t _reset, lws_button_idx_t _set)
|
|
{
|
|
lws_button_idx_t u = (bcs->enable_bitmap & (~_reset)) | _set;
|
|
const lws_button_controller_t *bc = bcs->controller;
|
|
int n;
|
|
|
|
for (n = 0; n < bcs->controller->count_buttons; n++) {
|
|
if (!(bcs->enable_bitmap & (1 << n)) && (u & (1 << n))) {
|
|
/* set as input with pullup or pulldown appropriately */
|
|
bc->gpio_ops->mode(bc->button_map[n].gpio,
|
|
LWSGGPIO_FL_READ |
|
|
((bc->active_state_bitmap & (1 << n)) ?
|
|
LWSGGPIO_FL_PULLDOWN : LWSGGPIO_FL_PULLUP));
|
|
/* this one is becoming enabled */
|
|
bc->gpio_ops->irq_mode(bc->button_map[n].gpio,
|
|
bc->active_state_bitmap & (1 << n) ?
|
|
LWSGGPIO_IRQ_RISING :
|
|
LWSGGPIO_IRQ_FALLING,
|
|
lws_button_irq_cb_t, bcs);
|
|
}
|
|
if ((bcs->enable_bitmap & (1 << n)) && !(u & (1 << n)))
|
|
/* this one is becoming disabled */
|
|
bc->gpio_ops->irq_mode(bc->button_map[n].gpio,
|
|
LWSGGPIO_IRQ_NONE, NULL, NULL);
|
|
}
|
|
|
|
bcs->enable_bitmap = u;
|
|
}
|