blob: 76ad07970cdb87eceec49171cdd075bd41d5fbb1 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <string.h>
#include "os/mynewt.h"
#include "debounce/debounce.h"
static void
debounce_check(void *arg)
{
debounce_pin_t *d = (debounce_pin_t*)arg;
int32_t btn = hal_gpio_read(d->pin) ? +1 : -1;
int32_t integrate = (int32_t)d->accu + btn;
if (integrate >= d->count) {
if (0 == d->state) {
d->state = 1;
if (d->on_rise && d->on_change) {
d->on_change(d);
}
}
integrate = d->count;
} else if ( integrate <= 0) {
if (1 == d->state) {
d->state = 0;
if (d->on_fall && d->on_change) {
d->on_change(d);
}
}
integrate = 0;
}
d->accu = integrate;
if (0 == integrate || d->count == integrate) {
/* debouncing complete, no point in periodically updating */
hal_gpio_irq_enable(d->pin);
} else {
/* no decision yet, continue debouncing */
hal_timer_start(&d->timer, d->ticks);
}
}
static void
debounce_trigger(void *arg)
{
debounce_pin_t *d = (debounce_pin_t*)arg;
/* once triggered, switch to periodic checks */
hal_gpio_irq_disable(d->pin);
hal_timer_start(&d->timer, d->ticks);
}
int
debounce_init(debounce_pin_t *d, int pin, hal_gpio_pull_t pull, int timer)
{
memset(d, 0, sizeof(debounce_pin_t));
d->pin = pin;
d->ticks = MYNEWT_VAL(DEBOUNCE_PARAM_TICKS);
d->count = MYNEWT_VAL(DEBOUNCE_PARAM_COUNT);
if (hal_timer_set_cb(timer, &d->timer, debounce_check, d)) {
return -1;
}
if (hal_gpio_irq_init(pin, debounce_trigger, d, HAL_GPIO_TRIG_BOTH, pull)) {
return -1;
}
if (hal_gpio_read(pin)) {
d->state = 1;
d->accu = d->count;
}
return 0;
}
int
debounce_set_params(debounce_pin_t *d, uint16_t ticks, uint8_t count)
{
d->ticks = ticks;
d->count = count;
if (d->state) {
d->accu = count;
}
return 0;
}
int
debounce_start(debounce_pin_t *d,
debounce_callback_event_t event,
debounce_callback_t cb,
void *arg)
{
d->on_rise = (event & DEBOUNCE_CALLBACK_EVENT_RISE) ? 1 : 0;
d->on_fall = (event & DEBOUNCE_CALLBACK_EVENT_FALL) ? 1 : 0;
d->on_change = cb;
d->arg = arg;
hal_gpio_irq_enable(d->pin);
return 0;
}
int
debounce_stop(debounce_pin_t *d)
{
hal_gpio_irq_disable(d->pin);
hal_timer_stop(&d->timer);
return 0;
}