summaryrefslogtreecommitdiff
path: root/src/gpio.cpp
blob: a7927a8a66e3796abcbde523bfa7e677aa4c9f22 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include "badge/gpio.h"

#include "badge/config.h"
#include "badge/log.h"

#include <Arduino.h>

#define BUTTON_PIN 0

#if UVOK_EPAP_BOARD == BOARD_ESP32_CROWPANEL
// Elecrow
#define EXIT_KEY 1
#define HOME_KEY 2
#define NEXT_KEY 4
#define OK_KEY 5
#define PRV_KEY 6
#endif

static void gpio_loop(void *);

typedef struct
{
    uint32_t timestamp;
    uint32_t pin : 8;
    uint32_t state : 1;
} pin_notification_t;

_Static_assert(sizeof(uint32_t) >= sizeof(unsigned long), "return type of millis");

#define GPIO_STACK 2048
#define GPIO_QUEUE_LEN 32
static unsigned long pressedTime = 0;
static unsigned long releasedTime = 0;

typedef struct
{
    uint32_t last_change;
    uint32_t last_level;
    uint32_t pressed;
} InputInfo_t;

static volatile InputInfo_t inputs[NUM_DIGITAL_PINS];

static struct
{

    StaticTask_t task;
    StackType_t task_stack[GPIO_STACK / sizeof(StackType_t)];

    StaticQueue_t queue;
    uint8_t queue_storage[GPIO_QUEUE_LEN * sizeof(pin_notification_t)];
    QueueHandle_t queue_handle;
} gpio_task_stuff;

static ARDUINO_ISR_ATTR void gpio_pin_irq(void *);

void de::uvok::badge::gpio_init(void)
{
    xTaskCreateStatic(gpio_loop, "gpio", GPIO_STACK, NULL, configMAX_PRIORITIES - 1, gpio_task_stuff.task_stack,
                      &gpio_task_stuff.task);
    gpio_task_stuff.queue_handle =
        xQueueCreateStatic(4, sizeof(pin_notification_t), &(gpio_task_stuff.queue_storage[0]), &gpio_task_stuff.queue);
#if UVOK_EPAP_BOARD == BOARD_ESP32_CROWPANEL
    uint8_t inPins[] = {EXIT_KEY, HOME_KEY, NEXT_KEY, OK_KEY, PRV_KEY};
    for (uint8_t p : inPins)
    {
        pinMode(p, GPIO_MODE_INPUT);
        // simply use pin number as arg
        attachInterruptArg(digitalPinToInterrupt(p), gpio_pin_irq, (void *)(ptrdiff_t)p, CHANGE);
        inputs[p].last_level = digitalRead(p);
    }
#endif
}

long de::uvok::badge::gpio_poll(void)
{
    int x = 0;
    static int lastState = HIGH;
    int buttonState = digitalRead(BUTTON_PIN);
    long pressDuration = 0;
    if (lastState == HIGH && buttonState == LOW)
    {
        Serial.println("``\\__");
        pressedTime = millis();
        lastState = LOW;
    }
    else if (lastState == LOW && buttonState == HIGH)
    {
        lastState = HIGH;
        Serial.println("__/``");
        releasedTime = millis();

        pressDuration = releasedTime - pressedTime;
    };

    return pressDuration;
}

static void gpio_loop(void *ctx)
{
    Serial.println("Starting GPIO loop");
    while (1)
    {
        pin_notification_t received;
        if (xQueueReceive(gpio_task_stuff.queue_handle, &received, portMAX_DELAY) == pdTRUE)
        {
            const bool pressed = !received.state;
            const uint8_t pin = received.pin;
            LOG_F("(%u) Pin %u was %s\n", received.timestamp, pin, pressed ? "pressed" : "released");
        }
    }
}

static ARDUINO_ISR_ATTR void gpio_pin_irq(void *arg)
{
    uint8_t pin_no = (uint8_t)(ptrdiff_t)arg;
    uint32_t now = millis();
    // Elecrow inputs - the selector - are very dirty...
    // const bool is_dirty = now - inputs[pin_no].last_change < 50;
    // inputs[pin_no].last_change = now;
    // if (is_dirty)
    //     return;

    int pinLevel = digitalRead(pin_no);

    pin_notification_t send = {.timestamp = now, .pin = pin_no, .state = (pinLevel == HIGH)};
    BaseType_t wakeup = false;
    xQueueSendFromISR(gpio_task_stuff.queue_handle, &send, &wakeup);
    if (wakeup)
    {
        portYIELD_FROM_ISR();
    }
}