waveblender/button.c
2020-04-13 11:11:17 +02:00

221 lines
4.9 KiB
C

/*
* (c) danielinux 2019
* GPLv.2
*
* See LICENSE for details
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "system.h"
#include "button.h"
#include "systick.h"
#include "unicore-mx/stm32/gpio.h"
#include "unicore-mx/stm32/exti.h"
#include "unicore-mx/stm32/rcc.h"
#include "unicore-mx/stm32/f4/rcc.h"
#include "unicore-mx/stm32/adc.h"
#include "unicore-mx/stm32/f4/adc.h"
#include "unicore-mx/stm32/f4/nvic.h"
// Uncomment to enable debug
//#define BUTTON_DEBUG
enum button_state {
IDLE = 0,
PRESSING,
PRESSED,
HOLD,
RELEASING,
};
#ifdef BUTTON_DEBUG
# define DBG printf
#else
# define DBG(...) do {} while (0)
#endif
#define BUTTON_DEBOUNCE_TIME 50
#define BUTTON_HOLD_TIME 200
static volatile int button_press_pending = 0;
#define BUTTON_PLUS '+'
#define BUTTON_MINUS '-'
static void input_run(uint32_t ev, void *arg);
static void input_init(void);
const char button_task_name[] = "Input";
// PA8 + PA9 // ROTARY encoder
// PC0 // BUTTON
//
// TODO:
// C4 + C5 rotary
// B0 + B1 + C3 Buttons (- + RotSW)
//
void pin_exti_init(void)
{
}
void pin_exti_start_read(void)
{
exti_set_trigger(GPIO0|GPIO1|GPIO3|GPIO4|GPIO5, EXTI_TRIGGER_BOTH);
exti_enable_request(GPIO0);
exti_enable_request(GPIO1);
exti_enable_request(GPIO3);
exti_enable_request(GPIO4);
exti_enable_request(GPIO5);
}
static void button_setup(void)
{
rcc_periph_clock_enable(RCC_SYSCFG);
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_GPIOC);
gpio_mode_setup(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO3 | GPIO4 | GPIO5);
gpio_mode_setup(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO0 | GPIO1);
nvic_enable_irq(NVIC_EXTI9_5_IRQ);
nvic_enable_irq(NVIC_EXTI0_IRQ);
nvic_enable_irq(NVIC_EXTI1_IRQ);
nvic_enable_irq(NVIC_EXTI3_IRQ);
nvic_enable_irq(NVIC_EXTI4_IRQ);
nvic_set_priority(NVIC_EXTI9_5_IRQ, 1);
nvic_set_priority(NVIC_EXTI0_IRQ, 1);
nvic_set_priority(NVIC_EXTI1_IRQ, 1);
nvic_set_priority(NVIC_EXTI3_IRQ, 1);
nvic_set_priority(NVIC_EXTI4_IRQ, 1);
exti_select_source(GPIO0, GPIOB);
exti_select_source(GPIO1, GPIOB);
exti_select_source(GPIO3, GPIOC);
exti_select_source(GPIO4, GPIOC);
exti_select_source(GPIO5, GPIOC);
}
static volatile uint32_t rot_up = 0;
static volatile uint32_t rot_down = 0;
static void button_start_read(void)
{
exti_set_trigger(GPIO0|GPIO1|GPIO3, EXTI_TRIGGER_RISING);
exti_set_trigger(GPIO4, EXTI_TRIGGER_FALLING);
exti_enable_request(GPIO0);
exti_enable_request(GPIO1);
exti_enable_request(GPIO3);
exti_enable_request(GPIO4);
}
static volatile uint32_t last_rot_ev = 0;
void isr_exti_rot0(void)
{
uint32_t rot_val = gpio_get(GPIOC, GPIO4 | GPIO5);
if ((jiffies - last_rot_ev) > 100) {
if ((rot_val & GPIO4) == 0) {
if ((rot_val & GPIO5) == 0)
rot_down++;
else
rot_up++;
}
}
exti_reset_request(GPIO4);
exti_reset_request(GPIO5);
}
void isr_exti_button(void)
{
uint32_t pending;
pending = (gpio_get(GPIOB, GPIO0|GPIO1));
if ((pending & GPIO0) != 0) {
button_press_pending = '-';
}
if ((pending & GPIO1) != 0) {
button_press_pending = '+';
}
if (!pending) {
pending = (gpio_get(GPIOC, GPIO3));
if ((pending & GPIO3) != 0) {
button_press_pending = '*';
}
}
exti_reset_request(GPIO0);
exti_reset_request(GPIO1);
exti_reset_request(GPIO3);
}
static uint32_t t0s, t0us;
static uint32_t t1s, t1us;
static uint32_t time_diff_ms(uint32_t s_a, uint32_t us_a, uint32_t s_b, uint32_t us_b)
{
uint32_t res = 0;
res = (s_a - s_b) * 1000;
if (us_b > us_a) {
us_a += 1000000;
res -= 1000;
}
res += (us_a - us_b) / 1000;
return res;
}
/* Button interface */
struct user_button
{
enum button_state state;
uint32_t transition_start_timestamp;
};
static struct user_button Buttons[N_BUTTONS];
int button_poll(void (*callback)(uint8_t press, int hold))
{
int b = 0;
int st;
static uint32_t last_event = 0;
static uint32_t pressed_start = 0;
while(rot_down > 0) {
callback('D',0);
rot_down--;
}
while(rot_up > 0) {
callback('U',0);
rot_up--;
}
if (jiffies - last_event < BUTTON_DEBOUNCE_TIME)
return;
last_event = jiffies;
st = !!(gpio_get(GPIOB, GPIO0 | GPIO1) | gpio_get(GPIOC, GPIO3));
if (!st) {
pressed_start = 0;
}
if ((button_press_pending) && st) {
if ((pressed_start == 0) || ((jiffies - pressed_start) > BUTTON_HOLD_TIME)) {
pressed_start = jiffies;
callback(button_press_pending, 0);
return 1;
}
}
button_press_pending = 0;
return 0;
}
void button_init(void)
{
memset(Buttons, 0, sizeof(struct user_button) * N_BUTTONS);
button_setup();
button_start_read();
}