summaryrefslogtreecommitdiff
path: root/src/kscan_mock.c
blob: a21433528a78fc08398312c661c1f12b2afdba14 (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
/*
 * Copyright (c) 2020 Peter Johanson <peter@peterjohanson.com>
 *
 * SPDX-License-Identifier: MIT
 */

#define DT_DRV_COMPAT zmk_kscan_mock

#include <device.h>
#include <drivers/kscan.h>
#include <logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

#include <zmk/kscan-mock.h>

#define MATRIX_NODE_ID DT_DRV_INST(0)
#define MATRIX_ROWS DT_PROP(MATRIX_NODE_ID, rows)
#define MATRIX_COLS DT_PROP(MATRIX_NODE_ID, columns)
#define MATRIX_MOCK_EVENT_COUNT DT_PROP_LEN(MATRIX_NODE_ID, events)

struct kscan_mock_config
{
    u32_t events[MATRIX_MOCK_EVENT_COUNT];
};

struct kscan_mock_data
{
    kscan_callback_t callback;

    u8_t event_index;
    struct k_delayed_work work;
    struct device *dev;
};

static void kscan_mock_schedule_next_event(struct device *dev)
{
    struct kscan_mock_data *data = dev->driver_data;
    const struct kscan_mock_config *cfg = dev->config_info;

    if (data->event_index < MATRIX_MOCK_EVENT_COUNT)
    {
        u32_t ev = cfg->events[data->event_index];
        LOG_DBG("delaying next keypress: %d", ZMK_MOCK_MSEC(ev));
        k_delayed_work_submit(&data->work, K_MSEC(ZMK_MOCK_MSEC(ev)));
    }
}

static int kscan_mock_enable_callback(struct device *dev)
{
    struct kscan_mock_data *data = dev->driver_data;
    kscan_mock_schedule_next_event(dev);
    return 0;
}

static int kscan_mock_disable_callback(struct device *dev)
{
    struct kscan_mock_data *data = dev->driver_data;
    const struct kscan_mock_config *cfg = dev->config_info;

    k_delayed_work_cancel(&data->work);
    return 0;
}

static void kscan_mock_work_handler(struct k_work *work)
{
    struct kscan_mock_data *data =
        CONTAINER_OF(work, struct kscan_mock_data, work);
    struct kscan_mock_config *cfg = data->dev->config_info;

    u32_t ev = cfg->events[data->event_index++];
    LOG_DBG("ev %u row %d column %d state %d\n", ev, ZMK_MOCK_ROW(ev), ZMK_MOCK_COL(ev), ZMK_MOCK_IS_PRESS(ev));
    data->callback(data->dev, ZMK_MOCK_ROW(ev), ZMK_MOCK_COL(ev), ZMK_MOCK_IS_PRESS(ev));
    kscan_mock_schedule_next_event(data->dev);
}

static int kscan_mock_configure(struct device *dev, kscan_callback_t callback)
{
    struct kscan_mock_data *data = dev->driver_data;

    if (!callback)
    {
        return -EINVAL;
    }

    data->event_index = 0;
    data->callback = callback;

    return 0;
}

static int kscan_mock_init(struct device *dev)
{
    struct kscan_mock_data *data = dev->driver_data;
    const struct kscan_mock_config *cfg = dev->config_info;

    data->dev = dev;
    k_delayed_work_init(&data->work, kscan_mock_work_handler);

    return 0;
}

static const struct kscan_driver_api mock_driver_api = {
    .config = kscan_mock_configure,
    .enable_callback = kscan_mock_enable_callback,
    .disable_callback = kscan_mock_disable_callback,
};

static const struct kscan_mock_config kscan_mock_config = {
    .events = DT_PROP(MATRIX_NODE_ID, events)};

static struct kscan_mock_data kscan_mock_data;

DEVICE_AND_API_INIT(kscan_mock, DT_INST_LABEL(0), kscan_mock_init,
                    &kscan_mock_data,
                    &kscan_mock_config,
                    APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
                    &mock_driver_api);