summaryrefslogtreecommitdiff
path: root/app/src/endpoints.c
blob: 4f56aa5cde44f54dc03785a32adfcfe9ce3a2b73 (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
134
135
136
137
138
139
140
141
142
143
144
145
/*
 * Copyright (c) 2020 The ZMK Contributors
 *
 * SPDX-License-Identifier: MIT
 */

#include <zmk/endpoints.h>
#include <zmk/hid.h>
#include <zmk/usb.h>
#include <zmk/hog.h>
#include <zmk/event-manager.h>
#include <zmk/events/usb-conn-state-changed.h>

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

enum endpoint {
    ENDPOINT_USB,
    ENDPOINT_BLE,
};

static enum endpoint current_endpoint =
    COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BLE), (ENDPOINT_BLE), (ENDPOINT_USB));

static int send_keypad_report() {
    struct zmk_hid_keypad_report *keypad_report = zmk_hid_get_keypad_report();

    switch (current_endpoint) {
#if IS_ENABLED(CONFIG_ZMK_USB)
    case ENDPOINT_USB: {
        int err = zmk_usb_hid_send_report((u8_t *)keypad_report, sizeof(*keypad_report));
        if (err) {
            LOG_ERR("FAILED TO SEND OVER USB: %d", err);
        }
        return err;
    }
#endif /* IS_ENABLED(CONFIG_ZMK_USB) */

#if IS_ENABLED(CONFIG_ZMK_BLE)
    case ENDPOINT_BLE: {
        int err = zmk_hog_send_keypad_report(&keypad_report->body);
        if (err) {
            LOG_ERR("FAILED TO SEND OVER HOG: %d", err);
        }
        return err;
    }
#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */

    default:
        LOG_ERR("Unsupported endpoint %d", current_endpoint);
        return -ENOTSUP;
    }
}

static int send_consumer_report() {
    struct zmk_hid_consumer_report *consumer_report = zmk_hid_get_consumer_report();

    switch (current_endpoint) {
#if IS_ENABLED(CONFIG_ZMK_USB)
    case ENDPOINT_USB: {
        int err = zmk_usb_hid_send_report((u8_t *)consumer_report, sizeof(*consumer_report));
        if (err) {
            LOG_ERR("FAILED TO SEND OVER USB: %d", err);
        }
        return err;
    }
#endif /* IS_ENABLED(CONFIG_ZMK_USB) */

#if IS_ENABLED(CONFIG_ZMK_BLE)
    case ENDPOINT_BLE: {
        int err = zmk_hog_send_consumer_report(&consumer_report->body);
        if (err) {
            LOG_ERR("FAILED TO SEND OVER HOG: %d", err);
        }
        return err;
    }
#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */

    default:
        LOG_ERR("Unsupported endpoint %d", current_endpoint);
        return -ENOTSUP;
    }
}

int zmk_endpoints_send_report(u8_t usage_page) {

    LOG_DBG("usage page 0x%02X", usage_page);
    switch (usage_page) {
    case USAGE_KEYPAD:
        return send_keypad_report();
    case USAGE_CONSUMER:
        return send_consumer_report();
    default:
        LOG_ERR("Unsupported usage page %d", usage_page);
        return -ENOTSUP;
    }
}

static bool is_usb_ready() {
#if IS_ENABLED(CONFIG_ZMK_USB)
    return zmk_usb_is_hid_ready();
#else
    return false;
#endif
}

static bool is_ble_ready() {
#if IS_ENABLED(CONFIG_ZMK_BLE)
    return zmk_ble_active_profile_is_connected();
#else
    return false;
#endif
}

static enum endpoint get_selected_endpoint() {
    if (is_ble_ready()) {
        if (is_usb_ready()) {
            LOG_DBG("Both endpoints ready. Selecting USB");
            // TODO: add user setting to control this
            return ENDPOINT_USB;
        }

        return ENDPOINT_BLE;
    }

    return ENDPOINT_USB;
}

static int endpoint_listener(const struct zmk_event_header *eh) {
    enum endpoint new_endpoint = get_selected_endpoint();

    if (new_endpoint != current_endpoint) {
        // TODO: send null report on previous endpoint
        current_endpoint = new_endpoint;
        LOG_INF("Endpoint changed: %d", current_endpoint);
    }

    return 0;
}

ZMK_LISTENER(endpoint_listener, endpoint_listener);
#if IS_ENABLED(CONFIG_USB)
ZMK_SUBSCRIPTION(endpoint_listener, usb_conn_state_changed);
#endif
// TODO: add BLE state subscription