diff options
Diffstat (limited to 'tmk_core/protocol/lufa')
| -rw-r--r-- | tmk_core/protocol/lufa/adafruit_ble.cpp | 701 | ||||
| -rw-r--r-- | tmk_core/protocol/lufa/adafruit_ble.h | 59 | ||||
| -rw-r--r-- | tmk_core/protocol/lufa/lufa.c | 48 | ||||
| -rw-r--r-- | tmk_core/protocol/lufa/lufa.h | 11 | ||||
| -rw-r--r-- | tmk_core/protocol/lufa/outputselect.c | 79 | ||||
| -rw-r--r-- | tmk_core/protocol/lufa/outputselect.h | 34 | ||||
| -rw-r--r-- | tmk_core/protocol/lufa/ringbuffer.hpp | 66 | 
7 files changed, 37 insertions, 961 deletions
| diff --git a/tmk_core/protocol/lufa/adafruit_ble.cpp b/tmk_core/protocol/lufa/adafruit_ble.cpp deleted file mode 100644 index 3f2cc35734..0000000000 --- a/tmk_core/protocol/lufa/adafruit_ble.cpp +++ /dev/null @@ -1,701 +0,0 @@ -#include "adafruit_ble.h" - -#include <stdio.h> -#include <stdlib.h> -#include <alloca.h> -#include "debug.h" -#include "timer.h" -#include "action_util.h" -#include "ringbuffer.hpp" -#include <string.h> -#include "spi_master.h" -#include "wait.h" -#include "analog.h" -#include "progmem.h" - -// These are the pin assignments for the 32u4 boards. -// You may define them to something else in your config.h -// if yours is wired up differently. -#ifndef AdafruitBleResetPin -#    define AdafruitBleResetPin D4 -#endif - -#ifndef AdafruitBleCSPin -#    define AdafruitBleCSPin B4 -#endif - -#ifndef AdafruitBleIRQPin -#    define AdafruitBleIRQPin E6 -#endif - -#ifndef AdafruitBleSpiClockSpeed -#    define AdafruitBleSpiClockSpeed 4000000UL  // SCK frequency -#endif - -#define SCK_DIVISOR (F_CPU / AdafruitBleSpiClockSpeed) - -#define SAMPLE_BATTERY -#define ConnectionUpdateInterval 1000 /* milliseconds */ - -#ifndef BATTERY_LEVEL_PIN -#    define BATTERY_LEVEL_PIN B5 -#endif - -static struct { -    bool is_connected; -    bool initialized; -    bool configured; - -#define ProbedEvents 1 -#define UsingEvents 2 -    bool event_flags; - -#ifdef SAMPLE_BATTERY -    uint16_t last_battery_update; -    uint32_t vbat; -#endif -    uint16_t last_connection_update; -} state; - -// Commands are encoded using SDEP and sent via SPI -// https://github.com/adafruit/Adafruit_BluefruitLE_nRF51/blob/master/SDEP.md - -#define SdepMaxPayload 16 -struct sdep_msg { -    uint8_t type; -    uint8_t cmd_low; -    uint8_t cmd_high; -    struct __attribute__((packed)) { -        uint8_t len : 7; -        uint8_t more : 1; -    }; -    uint8_t payload[SdepMaxPayload]; -} __attribute__((packed)); - -// The recv latency is relatively high, so when we're hammering keys quickly, -// we want to avoid waiting for the responses in the matrix loop.  We maintain -// a short queue for that.  Since there is quite a lot of space overhead for -// the AT command representation wrapped up in SDEP, we queue the minimal -// information here. - -enum queue_type { -    QTKeyReport,  // 1-byte modifier + 6-byte key report -    QTConsumer,   // 16-bit key code -#ifdef MOUSE_ENABLE -    QTMouseMove,  // 4-byte mouse report -#endif -}; - -struct queue_item { -    enum queue_type queue_type; -    uint16_t        added; -    union __attribute__((packed)) { -        struct __attribute__((packed)) { -            uint8_t modifier; -            uint8_t keys[6]; -        } key; - -        uint16_t consumer; -        struct __attribute__((packed)) { -            int8_t  x, y, scroll, pan; -            uint8_t buttons; -        } mousemove; -    }; -}; - -// Items that we wish to send -static RingBuffer<queue_item, 40> send_buf; -// Pending response; while pending, we can't send any more requests. -// This records the time at which we sent the command for which we -// are expecting a response. -static RingBuffer<uint16_t, 2> resp_buf; - -static bool process_queue_item(struct queue_item *item, uint16_t timeout); - -enum sdep_type { -    SdepCommand       = 0x10, -    SdepResponse      = 0x20, -    SdepAlert         = 0x40, -    SdepError         = 0x80, -    SdepSlaveNotReady = 0xFE,  // Try again later -    SdepSlaveOverflow = 0xFF,  // You read more data than is available -}; - -enum ble_cmd { -    BleInitialize = 0xBEEF, -    BleAtWrapper  = 0x0A00, -    BleUartTx     = 0x0A01, -    BleUartRx     = 0x0A02, -}; - -enum ble_system_event_bits { -    BleSystemConnected    = 0, -    BleSystemDisconnected = 1, -    BleSystemUartRx       = 8, -    BleSystemMidiRx       = 10, -}; - -#define SdepTimeout 150             /* milliseconds */ -#define SdepShortTimeout 10         /* milliseconds */ -#define SdepBackOff 25              /* microseconds */ -#define BatteryUpdateInterval 10000 /* milliseconds */ - -static bool at_command(const char *cmd, char *resp, uint16_t resplen, bool verbose, uint16_t timeout = SdepTimeout); -static bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose = false); - -// Send a single SDEP packet -static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) { -    spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR); -    uint16_t timerStart = timer_read(); -    bool     success    = false; -    bool     ready      = false; - -    do { -        ready = spi_write(msg->type) != SdepSlaveNotReady; -        if (ready) { -            break; -        } - -        // Release it and let it initialize -        spi_stop(); -        wait_us(SdepBackOff); -        spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR); -    } while (timer_elapsed(timerStart) < timeout); - -    if (ready) { -        // Slave is ready; send the rest of the packet -        spi_transmit(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)) + msg->len); -        success = true; -    } - -    spi_stop(); - -    return success; -} - -static inline void sdep_build_pkt(struct sdep_msg *msg, uint16_t command, const uint8_t *payload, uint8_t len, bool moredata) { -    msg->type     = SdepCommand; -    msg->cmd_low  = command & 0xFF; -    msg->cmd_high = command >> 8; -    msg->len      = len; -    msg->more     = (moredata && len == SdepMaxPayload) ? 1 : 0; - -    static_assert(sizeof(*msg) == 20, "msg is correctly packed"); - -    memcpy(msg->payload, payload, len); -} - -// Read a single SDEP packet -static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) { -    bool     success    = false; -    uint16_t timerStart = timer_read(); -    bool     ready      = false; - -    do { -        ready = readPin(AdafruitBleIRQPin); -        if (ready) { -            break; -        } -        wait_us(1); -    } while (timer_elapsed(timerStart) < timeout); - -    if (ready) { -        spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR); - -        do { -            // Read the command type, waiting for the data to be ready -            msg->type = spi_read(); -            if (msg->type == SdepSlaveNotReady || msg->type == SdepSlaveOverflow) { -                // Release it and let it initialize -                spi_stop(); -                wait_us(SdepBackOff); -                spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR); -                continue; -            } - -            // Read the rest of the header -            spi_receive(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload))); - -            // and get the payload if there is any -            if (msg->len <= SdepMaxPayload) { -                spi_receive(msg->payload, msg->len); -            } -            success = true; -            break; -        } while (timer_elapsed(timerStart) < timeout); - -        spi_stop(); -    } -    return success; -} - -static void resp_buf_read_one(bool greedy) { -    uint16_t last_send; -    if (!resp_buf.peek(last_send)) { -        return; -    } - -    if (readPin(AdafruitBleIRQPin)) { -        struct sdep_msg msg; - -    again: -        if (sdep_recv_pkt(&msg, SdepTimeout)) { -            if (!msg.more) { -                // We got it; consume this entry -                resp_buf.get(last_send); -                dprintf("recv latency %dms\n", TIMER_DIFF_16(timer_read(), last_send)); -            } - -            if (greedy && resp_buf.peek(last_send) && readPin(AdafruitBleIRQPin)) { -                goto again; -            } -        } - -    } else if (timer_elapsed(last_send) > SdepTimeout * 2) { -        dprintf("waiting_for_result: timeout, resp_buf size %d\n", (int)resp_buf.size()); - -        // Timed out: consume this entry -        resp_buf.get(last_send); -    } -} - -static void send_buf_send_one(uint16_t timeout = SdepTimeout) { -    struct queue_item item; - -    // Don't send anything more until we get an ACK -    if (!resp_buf.empty()) { -        return; -    } - -    if (!send_buf.peek(item)) { -        return; -    } -    if (process_queue_item(&item, timeout)) { -        // commit that peek -        send_buf.get(item); -        dprintf("send_buf_send_one: have %d remaining\n", (int)send_buf.size()); -    } else { -        dprint("failed to send, will retry\n"); -        wait_ms(SdepTimeout); -        resp_buf_read_one(true); -    } -} - -static void resp_buf_wait(const char *cmd) { -    bool didPrint = false; -    while (!resp_buf.empty()) { -        if (!didPrint) { -            dprintf("wait on buf for %s\n", cmd); -            didPrint = true; -        } -        resp_buf_read_one(true); -    } -} - -static bool ble_init(void) { -    state.initialized  = false; -    state.configured   = false; -    state.is_connected = false; - -    setPinInput(AdafruitBleIRQPin); - -    spi_init(); - -    // Perform a hardware reset -    setPinOutput(AdafruitBleResetPin); -    writePinHigh(AdafruitBleResetPin); -    writePinLow(AdafruitBleResetPin); -    wait_ms(10); -    writePinHigh(AdafruitBleResetPin); - -    wait_ms(1000);  // Give it a second to initialize - -    state.initialized = true; -    return state.initialized; -} - -static inline uint8_t min(uint8_t a, uint8_t b) { return a < b ? a : b; } - -static bool read_response(char *resp, uint16_t resplen, bool verbose) { -    char *dest = resp; -    char *end  = dest + resplen; - -    while (true) { -        struct sdep_msg msg; - -        if (!sdep_recv_pkt(&msg, 2 * SdepTimeout)) { -            dprint("sdep_recv_pkt failed\n"); -            return false; -        } - -        if (msg.type != SdepResponse) { -            *resp = 0; -            return false; -        } - -        uint8_t len = min(msg.len, end - dest); -        if (len > 0) { -            memcpy(dest, msg.payload, len); -            dest += len; -        } - -        if (!msg.more) { -            // No more data is expected! -            break; -        } -    } - -    // Ensure the response is NUL terminated -    *dest = 0; - -    // "Parse" the result text; we want to snip off the trailing OK or ERROR line -    // Rewind past the possible trailing CRLF so that we can strip it -    --dest; -    while (dest > resp && (dest[0] == '\n' || dest[0] == '\r')) { -        *dest = 0; -        --dest; -    } - -    // Look back for start of preceeding line -    char *last_line = strrchr(resp, '\n'); -    if (last_line) { -        ++last_line; -    } else { -        last_line = resp; -    } - -    bool              success       = false; -    static const char kOK[] PROGMEM = "OK"; - -    success = !strcmp_P(last_line, kOK); - -    if (verbose || !success) { -        dprintf("result: %s\n", resp); -    } -    return success; -} - -static bool at_command(const char *cmd, char *resp, uint16_t resplen, bool verbose, uint16_t timeout) { -    const char *    end = cmd + strlen(cmd); -    struct sdep_msg msg; - -    if (verbose) { -        dprintf("ble send: %s\n", cmd); -    } - -    if (resp) { -        // They want to decode the response, so we need to flush and wait -        // for all pending I/O to finish before we start this one, so -        // that we don't confuse the results -        resp_buf_wait(cmd); -        *resp = 0; -    } - -    // Fragment the command into a series of SDEP packets -    while (end - cmd > SdepMaxPayload) { -        sdep_build_pkt(&msg, BleAtWrapper, (uint8_t *)cmd, SdepMaxPayload, true); -        if (!sdep_send_pkt(&msg, timeout)) { -            return false; -        } -        cmd += SdepMaxPayload; -    } - -    sdep_build_pkt(&msg, BleAtWrapper, (uint8_t *)cmd, end - cmd, false); -    if (!sdep_send_pkt(&msg, timeout)) { -        return false; -    } - -    if (resp == NULL) { -        uint16_t now = timer_read(); -        while (!resp_buf.enqueue(now)) { -            resp_buf_read_one(false); -        } -        uint16_t later = timer_read(); -        if (TIMER_DIFF_16(later, now) > 0) { -            dprintf("waited %dms for resp_buf\n", TIMER_DIFF_16(later, now)); -        } -        return true; -    } - -    return read_response(resp, resplen, verbose); -} - -bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose) { -    char *cmdbuf = (char *)alloca(strlen_P(cmd) + 1); -    strcpy_P(cmdbuf, cmd); -    return at_command(cmdbuf, resp, resplen, verbose); -} - -bool adafruit_ble_is_connected(void) { return state.is_connected; } - -bool adafruit_ble_enable_keyboard(void) { -    char resbuf[128]; - -    if (!state.initialized && !ble_init()) { -        return false; -    } - -    state.configured = false; - -    // Disable command echo -    static const char kEcho[] PROGMEM = "ATE=0"; -    // Make the advertised name match the keyboard -    static const char kGapDevName[] PROGMEM = "AT+GAPDEVNAME=" STR(PRODUCT); -    // Turn on keyboard support -    static const char kHidEnOn[] PROGMEM = "AT+BLEHIDEN=1"; - -    // Adjust intervals to improve latency.  This causes the "central" -    // system (computer/tablet) to poll us every 10-30 ms.  We can't -    // set a smaller value than 10ms, and 30ms seems to be the natural -    // processing time on my macbook.  Keeping it constrained to that -    // feels reasonable to type to. -    static const char kGapIntervals[] PROGMEM = "AT+GAPINTERVALS=10,30,,"; - -    // Reset the device so that it picks up the above changes -    static const char kATZ[] PROGMEM = "ATZ"; - -    // Turn down the power level a bit -    static const char  kPower[] PROGMEM             = "AT+BLEPOWERLEVEL=-12"; -    static PGM_P const configure_commands[] PROGMEM = { -        kEcho, kGapIntervals, kGapDevName, kHidEnOn, kPower, kATZ, -    }; - -    uint8_t i; -    for (i = 0; i < sizeof(configure_commands) / sizeof(configure_commands[0]); ++i) { -        PGM_P cmd; -        memcpy_P(&cmd, configure_commands + i, sizeof(cmd)); - -        if (!at_command_P(cmd, resbuf, sizeof(resbuf))) { -            dprintf("failed BLE command: %S: %s\n", cmd, resbuf); -            goto fail; -        } -    } - -    state.configured = true; - -    // Check connection status in a little while; allow the ATZ time -    // to kick in. -    state.last_connection_update = timer_read(); -fail: -    return state.configured; -} - -static void set_connected(bool connected) { -    if (connected != state.is_connected) { -        if (connected) { -            dprint("BLE connected\n"); -        } else { -            dprint("BLE disconnected\n"); -        } -        state.is_connected = connected; - -        // TODO: if modifiers are down on the USB interface and -        // we cut over to BLE or vice versa, they will remain stuck. -        // This feels like a good point to do something like clearing -        // the keyboard and/or generating a fake all keys up message. -        // However, I've noticed that it takes a couple of seconds -        // for macOS to to start recognizing key presses after BLE -        // is in the connected state, so I worry that doing that -        // here may not be good enough. -    } -} - -void adafruit_ble_task(void) { -    char resbuf[48]; - -    if (!state.configured && !adafruit_ble_enable_keyboard()) { -        return; -    } -    resp_buf_read_one(true); -    send_buf_send_one(SdepShortTimeout); - -    if (resp_buf.empty() && (state.event_flags & UsingEvents) && readPin(AdafruitBleIRQPin)) { -        // Must be an event update -        if (at_command_P(PSTR("AT+EVENTSTATUS"), resbuf, sizeof(resbuf))) { -            uint32_t mask = strtoul(resbuf, NULL, 16); - -            if (mask & BleSystemConnected) { -                set_connected(true); -            } else if (mask & BleSystemDisconnected) { -                set_connected(false); -            } -        } -    } - -    if (timer_elapsed(state.last_connection_update) > ConnectionUpdateInterval) { -        bool shouldPoll = true; -        if (!(state.event_flags & ProbedEvents)) { -            // Request notifications about connection status changes. -            // This only works in SPIFRIEND firmware > 0.6.7, which is why -            // we check for this conditionally here. -            // Note that at the time of writing, HID reports only work correctly -            // with Apple products on firmware version 0.6.7! -            // https://forums.adafruit.com/viewtopic.php?f=8&t=104052 -            if (at_command_P(PSTR("AT+EVENTENABLE=0x1"), resbuf, sizeof(resbuf))) { -                at_command_P(PSTR("AT+EVENTENABLE=0x2"), resbuf, sizeof(resbuf)); -                state.event_flags |= UsingEvents; -            } -            state.event_flags |= ProbedEvents; - -            // leave shouldPoll == true so that we check at least once -            // before relying solely on events -        } else { -            shouldPoll = false; -        } - -        static const char kGetConn[] PROGMEM = "AT+GAPGETCONN"; -        state.last_connection_update         = timer_read(); - -        if (at_command_P(kGetConn, resbuf, sizeof(resbuf))) { -            set_connected(atoi(resbuf)); -        } -    } - -#ifdef SAMPLE_BATTERY -    if (timer_elapsed(state.last_battery_update) > BatteryUpdateInterval && resp_buf.empty()) { -        state.last_battery_update = timer_read(); - -        state.vbat = analogReadPin(BATTERY_LEVEL_PIN); -    } -#endif -} - -static bool process_queue_item(struct queue_item *item, uint16_t timeout) { -    char cmdbuf[48]; -    char fmtbuf[64]; - -    // Arrange to re-check connection after keys have settled -    state.last_connection_update = timer_read(); - -#if 1 -    if (TIMER_DIFF_16(state.last_connection_update, item->added) > 0) { -        dprintf("send latency %dms\n", TIMER_DIFF_16(state.last_connection_update, item->added)); -    } -#endif - -    switch (item->queue_type) { -        case QTKeyReport: -            strcpy_P(fmtbuf, PSTR("AT+BLEKEYBOARDCODE=%02x-00-%02x-%02x-%02x-%02x-%02x-%02x")); -            snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->key.modifier, item->key.keys[0], item->key.keys[1], item->key.keys[2], item->key.keys[3], item->key.keys[4], item->key.keys[5]); -            return at_command(cmdbuf, NULL, 0, true, timeout); - -        case QTConsumer: -            strcpy_P(fmtbuf, PSTR("AT+BLEHIDCONTROLKEY=0x%04x")); -            snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->consumer); -            return at_command(cmdbuf, NULL, 0, true, timeout); - -#ifdef MOUSE_ENABLE -        case QTMouseMove: -            strcpy_P(fmtbuf, PSTR("AT+BLEHIDMOUSEMOVE=%d,%d,%d,%d")); -            snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->mousemove.x, item->mousemove.y, item->mousemove.scroll, item->mousemove.pan); -            if (!at_command(cmdbuf, NULL, 0, true, timeout)) { -                return false; -            } -            strcpy_P(cmdbuf, PSTR("AT+BLEHIDMOUSEBUTTON=")); -            if (item->mousemove.buttons & MOUSE_BTN1) { -                strcat(cmdbuf, "L"); -            } -            if (item->mousemove.buttons & MOUSE_BTN2) { -                strcat(cmdbuf, "R"); -            } -            if (item->mousemove.buttons & MOUSE_BTN3) { -                strcat(cmdbuf, "M"); -            } -            if (item->mousemove.buttons == 0) { -                strcat(cmdbuf, "0"); -            } -            return at_command(cmdbuf, NULL, 0, true, timeout); -#endif -        default: -            return true; -    } -} - -void adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys) { -    struct queue_item item; -    bool              didWait = false; - -    item.queue_type   = QTKeyReport; -    item.key.modifier = hid_modifier_mask; -    item.added        = timer_read(); - -    while (nkeys >= 0) { -        item.key.keys[0] = keys[0]; -        item.key.keys[1] = nkeys >= 1 ? keys[1] : 0; -        item.key.keys[2] = nkeys >= 2 ? keys[2] : 0; -        item.key.keys[3] = nkeys >= 3 ? keys[3] : 0; -        item.key.keys[4] = nkeys >= 4 ? keys[4] : 0; -        item.key.keys[5] = nkeys >= 5 ? keys[5] : 0; - -        if (!send_buf.enqueue(item)) { -            if (!didWait) { -                dprint("wait for buf space\n"); -                didWait = true; -            } -            send_buf_send_one(); -            continue; -        } - -        if (nkeys <= 6) { -            return; -        } - -        nkeys -= 6; -        keys += 6; -    } -} - -void adafruit_ble_send_consumer_key(uint16_t usage) { -    struct queue_item item; - -    item.queue_type = QTConsumer; -    item.consumer   = usage; - -    while (!send_buf.enqueue(item)) { -        send_buf_send_one(); -    } -} - -#ifdef MOUSE_ENABLE -void adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons) { -    struct queue_item item; - -    item.queue_type        = QTMouseMove; -    item.mousemove.x       = x; -    item.mousemove.y       = y; -    item.mousemove.scroll  = scroll; -    item.mousemove.pan     = pan; -    item.mousemove.buttons = buttons; - -    while (!send_buf.enqueue(item)) { -        send_buf_send_one(); -    } -} -#endif - -uint32_t adafruit_ble_read_battery_voltage(void) { return state.vbat; } - -bool adafruit_ble_set_mode_leds(bool on) { -    if (!state.configured) { -        return false; -    } - -    // The "mode" led is the red blinky one -    at_command_P(on ? PSTR("AT+HWMODELED=1") : PSTR("AT+HWMODELED=0"), NULL, 0); - -    // Pin 19 is the blue "connected" LED; turn that off too. -    // When turning LEDs back on, don't turn that LED on if we're -    // not connected, as that would be confusing. -    at_command_P(on && state.is_connected ? PSTR("AT+HWGPIO=19,1") : PSTR("AT+HWGPIO=19,0"), NULL, 0); -    return true; -} - -// https://learn.adafruit.com/adafruit-feather-32u4-bluefruit-le/ble-generic#at-plus-blepowerlevel -bool adafruit_ble_set_power_level(int8_t level) { -    char cmd[46]; -    if (!state.configured) { -        return false; -    } -    snprintf(cmd, sizeof(cmd), "AT+BLEPOWERLEVEL=%d", level); -    return at_command(cmd, NULL, 0, false); -} diff --git a/tmk_core/protocol/lufa/adafruit_ble.h b/tmk_core/protocol/lufa/adafruit_ble.h deleted file mode 100644 index b43e0771d9..0000000000 --- a/tmk_core/protocol/lufa/adafruit_ble.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Bluetooth Low Energy Protocol for QMK. - * Author: Wez Furlong, 2016 - * Supports the Adafruit BLE board built around the nRF51822 chip. - */ - -#pragma once - -#include <stdbool.h> -#include <stdint.h> -#include <string.h> - -#include "config_common.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Instruct the module to enable HID keyboard support and reset */ -extern bool adafruit_ble_enable_keyboard(void); - -/* Query to see if the BLE module is connected */ -extern bool adafruit_ble_query_is_connected(void); - -/* Returns true if we believe that the BLE module is connected. - * This uses our cached understanding that is maintained by - * calling ble_task() periodically. */ -extern bool adafruit_ble_is_connected(void); - -/* Call this periodically to process BLE-originated things */ -extern void adafruit_ble_task(void); - -/* Generates keypress events for a set of keys. - * The hid modifier mask specifies the state of the modifier keys for - * this set of keys. - * Also sends a key release indicator, so that the keys do not remain - * held down. */ -extern void adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys); - -/* Send a consumer usage. - * (milliseconds) */ -extern void adafruit_ble_send_consumer_key(uint16_t usage); - -#ifdef MOUSE_ENABLE -/* Send a mouse/wheel movement report. - * The parameters are signed and indicate positive or negative direction - * change. */ -extern void adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons); -#endif - -/* Compute battery voltage by reading an analog pin. - * Returns the integer number of millivolts */ -extern uint32_t adafruit_ble_read_battery_voltage(void); - -extern bool adafruit_ble_set_mode_leds(bool on); -extern bool adafruit_ble_set_power_level(int8_t level); - -#ifdef __cplusplus -} -#endif diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index 5b56e8a03c..753762358d 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -52,6 +52,7 @@  #include "usb_descriptor.h"  #include "lufa.h"  #include "quantum.h" +#include "usb_device_state.h"  #include <util/atomic.h>  #ifdef NKRO_ENABLE @@ -142,7 +143,8 @@ static void    send_keyboard(report_keyboard_t *report);  static void    send_mouse(report_mouse_t *report);  static void    send_system(uint16_t data);  static void    send_consumer(uint16_t data); -host_driver_t  lufa_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer}; +static void    send_programmable_button(uint32_t data); +host_driver_t  lufa_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer, send_programmable_button};  #ifdef VIRTSER_ENABLE  // clang-format off @@ -413,7 +415,10 @@ void EVENT_USB_Device_Disconnect(void) {   *   * FIXME: Needs doc   */ -void EVENT_USB_Device_Reset(void) { print("[R]"); } +void EVENT_USB_Device_Reset(void) { +    print("[R]"); +    usb_device_state_set_reset(); +}  /** \brief Event USB Device Connect   * @@ -421,6 +426,8 @@ void EVENT_USB_Device_Reset(void) { print("[R]"); }   */  void EVENT_USB_Device_Suspend() {      print("[S]"); +    usb_device_state_set_suspend(USB_Device_ConfigurationNumber != 0, USB_Device_ConfigurationNumber); +  #ifdef SLEEP_LED_ENABLE      sleep_led_enable();  #endif @@ -436,6 +443,8 @@ void EVENT_USB_Device_WakeUp() {      suspend_wakeup_init();  #endif +    usb_device_state_set_resume(USB_DeviceState == DEVICE_STATE_Configured, USB_Device_ConfigurationNumber); +  #ifdef SLEEP_LED_ENABLE      sleep_led_disable();      // NOTE: converters may not accept this @@ -528,6 +537,8 @@ void EVENT_USB_Device_ConfigurationChanged(void) {      /* Setup digitizer endpoint */      ConfigSuccess &= Endpoint_ConfigureEndpoint((DIGITIZER_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_INTERRUPT, DIGITIZER_EPSIZE, 1);  #endif + +    usb_device_state_set_configuration(USB_DeviceState == DEVICE_STATE_Configured, USB_Device_ConfigurationNumber);  }  /* FIXME: Expose this table in the docs somehow @@ -760,29 +771,35 @@ static void send_mouse(report_mouse_t *report) {  #endif  } -/** \brief Send Extra - * - * FIXME: Needs doc - */ -#ifdef EXTRAKEY_ENABLE -static void send_extra(uint8_t report_id, uint16_t data) { +#if defined(EXTRAKEY_ENABLE) || defined(PROGRAMMABLE_BUTTON_ENABLE) +static void send_report(void *report, size_t size) {      uint8_t timeout = 255;      if (USB_DeviceState != DEVICE_STATE_Configured) return; -    static report_extra_t r; -    r = (report_extra_t){.report_id = report_id, .usage = data};      Endpoint_SelectEndpoint(SHARED_IN_EPNUM);      /* Check if write ready for a polling interval around 10ms */      while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);      if (!Endpoint_IsReadWriteAllowed()) return; -    Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL); +    Endpoint_Write_Stream_LE(report, size, NULL);      Endpoint_ClearIN();  }  #endif +/** \brief Send Extra + * + * FIXME: Needs doc + */ +#ifdef EXTRAKEY_ENABLE +static void send_extra(uint8_t report_id, uint16_t data) { +    static report_extra_t r; +    r = (report_extra_t){.report_id = report_id, .usage = data}; +    send_report(&r, sizeof(r)); +} +#endif +  /** \brief Send System   *   * FIXME: Needs doc @@ -822,6 +839,14 @@ static void send_consumer(uint16_t data) {  #endif  } +static void send_programmable_button(uint32_t data) { +#ifdef PROGRAMMABLE_BUTTON_ENABLE +    static report_programmable_button_t r; +    r = (report_programmable_button_t){.report_id = REPORT_ID_PROGRAMMABLE_BUTTON, .usage = data}; +    send_report(&r, sizeof(r)); +#endif +} +  /*******************************************************************************   * sendchar   ******************************************************************************/ @@ -1044,6 +1069,7 @@ void protocol_setup(void) {  #endif      setup_mcu(); +    usb_device_state_init();      keyboard_setup();  } diff --git a/tmk_core/protocol/lufa/lufa.h b/tmk_core/protocol/lufa/lufa.h index 348a84c031..6a5205609e 100644 --- a/tmk_core/protocol/lufa/lufa.h +++ b/tmk_core/protocol/lufa/lufa.h @@ -56,14 +56,3 @@ extern host_driver_t lufa_driver;  #ifdef __cplusplus  }  #endif - -#ifdef API_ENABLE -#    include "api.h" -#endif - -#ifdef API_SYSEX_ENABLE -#    include "api_sysex.h" -// Allocate space for encoding overhead. -// The header and terminator are not stored to save a few bytes of precious ram -#    define MIDI_SYSEX_BUFFER (API_SYSEX_MAX_SIZE + API_SYSEX_MAX_SIZE / 7 + (API_SYSEX_MAX_SIZE % 7 ? 1 : 0)) -#endif diff --git a/tmk_core/protocol/lufa/outputselect.c b/tmk_core/protocol/lufa/outputselect.c deleted file mode 100644 index f758c65280..0000000000 --- a/tmk_core/protocol/lufa/outputselect.c +++ /dev/null @@ -1,79 +0,0 @@ -/* -Copyright 2017 Priyadi Iman Nurcahyo -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with this program.  If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "outputselect.h" - -#if defined(PROTOCOL_LUFA) -#    include "lufa.h" -#endif - -#ifdef MODULE_ADAFRUIT_BLE -#    include "adafruit_ble.h" -#endif - -uint8_t desired_output = OUTPUT_DEFAULT; - -/** \brief Set Output - * - * FIXME: Needs doc - */ -void set_output(uint8_t output) { -    set_output_user(output); -    desired_output = output; -} - -/** \brief Set Output User - * - * FIXME: Needs doc - */ -__attribute__((weak)) void set_output_user(uint8_t output) {} - -static bool is_usb_configured(void) { -#if defined(PROTOCOL_LUFA) -    return USB_DeviceState == DEVICE_STATE_Configured; -#endif -} - -/** \brief Auto Detect Output - * - * FIXME: Needs doc - */ -uint8_t auto_detect_output(void) { -    if (is_usb_configured()) { -        return OUTPUT_USB; -    } - -#ifdef MODULE_ADAFRUIT_BLE -    if (adafruit_ble_is_connected()) { -        return OUTPUT_BLUETOOTH; -    } -#endif - -#ifdef BLUETOOTH_ENABLE -    return OUTPUT_BLUETOOTH;  // should check if BT is connected here -#endif - -    return OUTPUT_NONE; -} - -/** \brief Where To Send - * - * FIXME: Needs doc - */ -uint8_t where_to_send(void) { -    if (desired_output == OUTPUT_AUTO) { -        return auto_detect_output(); -    } -    return desired_output; -} diff --git a/tmk_core/protocol/lufa/outputselect.h b/tmk_core/protocol/lufa/outputselect.h deleted file mode 100644 index c4548e1122..0000000000 --- a/tmk_core/protocol/lufa/outputselect.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -Copyright 2017 Priyadi Iman Nurcahyo -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with this program.  If not, see <http://www.gnu.org/licenses/>. -*/ - -#pragma once - -#include <stdint.h> - -enum outputs { -    OUTPUT_AUTO, - -    OUTPUT_NONE, -    OUTPUT_USB, -    OUTPUT_BLUETOOTH -}; - -#ifndef OUTPUT_DEFAULT -#    define OUTPUT_DEFAULT OUTPUT_AUTO -#endif - -void    set_output(uint8_t output); -void    set_output_user(uint8_t output); -uint8_t auto_detect_output(void); -uint8_t where_to_send(void); diff --git a/tmk_core/protocol/lufa/ringbuffer.hpp b/tmk_core/protocol/lufa/ringbuffer.hpp deleted file mode 100644 index 70a3c4881d..0000000000 --- a/tmk_core/protocol/lufa/ringbuffer.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once -// A simple ringbuffer holding Size elements of type T -template <typename T, uint8_t Size> -class RingBuffer { - protected: -  T buf_[Size]; -  uint8_t head_{0}, tail_{0}; - public: -  inline uint8_t nextPosition(uint8_t position) { -    return (position + 1) % Size; -  } - -  inline uint8_t prevPosition(uint8_t position) { -    if (position == 0) { -      return Size - 1; -    } -    return position - 1; -  } - -  inline bool enqueue(const T &item) { -    static_assert(Size > 1, "RingBuffer size must be > 1"); -    uint8_t next = nextPosition(head_); -    if (next == tail_) { -      // Full -      return false; -    } - -    buf_[head_] = item; -    head_ = next; -    return true; -  } - -  inline bool get(T &dest, bool commit = true) { -    auto tail = tail_; -    if (tail == head_) { -      // No more data -      return false; -    } - -    dest = buf_[tail]; -    tail = nextPosition(tail); - -    if (commit) { -      tail_ = tail; -    } -    return true; -  } - -  inline bool empty() const { return head_ == tail_; } - -  inline uint8_t size() const { -    int diff = head_ - tail_; -    if (diff >= 0) { -      return diff; -    } -    return Size + diff; -  } - -  inline T& front() { -    return buf_[tail_]; -  } - -  inline bool peek(T &item) { -    return get(item, false); -  } -}; | 
