From a24ce02167fc047372c3041786c8d13bf94a9527 Mon Sep 17 00:00:00 2001 From: Jacek Fedorynski Date: Thu, 2 Nov 2023 21:42:47 +0100 Subject: [PATCH] GPIO outputs Adds the possibility to set a GPIO pin as the target of a mapping. Also makes all otherwise unused pins available for input/output (previously limited to GPIO2-GPIO9). --- config-tool-web/usages.js | 52 ++++++++++++++++++++++++++++++ firmware-bluetooth/src/main.cc | 3 ++ firmware/CMakeLists.txt | 4 +++ firmware/src/boards/feather_host.h | 2 ++ firmware/src/boards/remapper.h | 2 ++ firmware/src/globals.cc | 2 ++ firmware/src/globals.h | 2 ++ firmware/src/main.cc | 38 +++++++++++++++------- firmware/src/pico_debug/swd.c | 8 ----- firmware/src/pico_debug/swd.h | 8 +++++ firmware/src/platform.h | 3 ++ firmware/src/remapper.cc | 44 ++++++++++++++++++++----- firmware/src/remapper.h | 2 ++ firmware/src/remapper_dual_a.cc | 13 ++++++++ firmware/src/remapper_serial.cc | 8 +++++ firmware/src/remapper_single.cc | 9 ++++++ firmware/src/serial.cc | 16 --------- firmware/src/serial.h | 16 +++++++++ 18 files changed, 189 insertions(+), 43 deletions(-) diff --git a/config-tool-web/usages.js b/config-tool-web/usages.js index 246a44a..e4404fa 100644 --- a/config-tool-web/usages.js +++ b/config-tool-web/usages.js @@ -196,6 +196,8 @@ const usages = { "0xfff5001e": { 'name': 'Register 30', 'class': 'other' }, "0xfff5001f": { 'name': 'Register 31', 'class': 'other' }, "0xfff50020": { 'name': 'Register 32', 'class': 'other' }, + "0xfff40000": { 'name': 'GPIO 0', 'class': 'other' }, + "0xfff40001": { 'name': 'GPIO 1', 'class': 'other' }, "0xfff40002": { 'name': 'GPIO 2', 'class': 'other' }, "0xfff40003": { 'name': 'GPIO 3', 'class': 'other' }, "0xfff40004": { 'name': 'GPIO 4', 'class': 'other' }, @@ -204,6 +206,26 @@ const usages = { "0xfff40007": { 'name': 'GPIO 7', 'class': 'other' }, "0xfff40008": { 'name': 'GPIO 8', 'class': 'other' }, "0xfff40009": { 'name': 'GPIO 9', 'class': 'other' }, + "0xfff4000a": { 'name': 'GPIO 10', 'class': 'other' }, + "0xfff4000b": { 'name': 'GPIO 11', 'class': 'other' }, + "0xfff4000c": { 'name': 'GPIO 12', 'class': 'other' }, + "0xfff4000d": { 'name': 'GPIO 13', 'class': 'other' }, + "0xfff4000e": { 'name': 'GPIO 14', 'class': 'other' }, + "0xfff4000f": { 'name': 'GPIO 15', 'class': 'other' }, + "0xfff40010": { 'name': 'GPIO 16', 'class': 'other' }, + "0xfff40011": { 'name': 'GPIO 17', 'class': 'other' }, + "0xfff40012": { 'name': 'GPIO 18', 'class': 'other' }, + "0xfff40013": { 'name': 'GPIO 19', 'class': 'other' }, + "0xfff40014": { 'name': 'GPIO 20', 'class': 'other' }, + "0xfff40015": { 'name': 'GPIO 21', 'class': 'other' }, + "0xfff40016": { 'name': 'GPIO 22', 'class': 'other' }, + "0xfff40017": { 'name': 'GPIO 23', 'class': 'other' }, + "0xfff40018": { 'name': 'GPIO 24', 'class': 'other' }, + "0xfff40019": { 'name': 'GPIO 25', 'class': 'other' }, + "0xfff4001a": { 'name': 'GPIO 26', 'class': 'other' }, + "0xfff4001b": { 'name': 'GPIO 27', 'class': 'other' }, + "0xfff4001c": { 'name': 'GPIO 28', 'class': 'other' }, + "0xfff4001d": { 'name': 'GPIO 29', 'class': 'other' }, }, 0: { "0x00090001": { 'name': 'Left button', 'class': 'mouse' }, @@ -446,6 +468,36 @@ const common_target_usages = { "0xfff2001e": { 'name': 'Macro 30', 'class': 'other' }, "0xfff2001f": { 'name': 'Macro 31', 'class': 'other' }, "0xfff20020": { 'name': 'Macro 32', 'class': 'other' }, + "0xfff40000": { 'name': 'GPIO 0', 'class': 'other' }, + "0xfff40001": { 'name': 'GPIO 1', 'class': 'other' }, + "0xfff40002": { 'name': 'GPIO 2', 'class': 'other' }, + "0xfff40003": { 'name': 'GPIO 3', 'class': 'other' }, + "0xfff40004": { 'name': 'GPIO 4', 'class': 'other' }, + "0xfff40005": { 'name': 'GPIO 5', 'class': 'other' }, + "0xfff40006": { 'name': 'GPIO 6', 'class': 'other' }, + "0xfff40007": { 'name': 'GPIO 7', 'class': 'other' }, + "0xfff40008": { 'name': 'GPIO 8', 'class': 'other' }, + "0xfff40009": { 'name': 'GPIO 9', 'class': 'other' }, + "0xfff4000a": { 'name': 'GPIO 10', 'class': 'other' }, + "0xfff4000b": { 'name': 'GPIO 11', 'class': 'other' }, + "0xfff4000c": { 'name': 'GPIO 12', 'class': 'other' }, + "0xfff4000d": { 'name': 'GPIO 13', 'class': 'other' }, + "0xfff4000e": { 'name': 'GPIO 14', 'class': 'other' }, + "0xfff4000f": { 'name': 'GPIO 15', 'class': 'other' }, + "0xfff40010": { 'name': 'GPIO 16', 'class': 'other' }, + "0xfff40011": { 'name': 'GPIO 17', 'class': 'other' }, + "0xfff40012": { 'name': 'GPIO 18', 'class': 'other' }, + "0xfff40013": { 'name': 'GPIO 19', 'class': 'other' }, + "0xfff40014": { 'name': 'GPIO 20', 'class': 'other' }, + "0xfff40015": { 'name': 'GPIO 21', 'class': 'other' }, + "0xfff40016": { 'name': 'GPIO 22', 'class': 'other' }, + "0xfff40017": { 'name': 'GPIO 23', 'class': 'other' }, + "0xfff40018": { 'name': 'GPIO 24', 'class': 'other' }, + "0xfff40019": { 'name': 'GPIO 25', 'class': 'other' }, + "0xfff4001a": { 'name': 'GPIO 26', 'class': 'other' }, + "0xfff4001b": { 'name': 'GPIO 27', 'class': 'other' }, + "0xfff4001c": { 'name': 'GPIO 28', 'class': 'other' }, + "0xfff4001d": { 'name': 'GPIO 29', 'class': 'other' }, } Object.assign(usages[0], common_target_usages); diff --git a/firmware-bluetooth/src/main.cc b/firmware-bluetooth/src/main.cc index 83b0a36..f2738f1 100644 --- a/firmware-bluetooth/src/main.cc +++ b/firmware-bluetooth/src/main.cc @@ -827,6 +827,9 @@ void queue_get_feature_report(uint16_t interface, uint8_t report_id, uint8_t len // TODO } +void set_gpio_inout_masks(uint32_t in_mask, uint32_t out_mask) { +} + int main() { LOG_INF("HID Remapper Bluetooth"); diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt index 509940b..3c814ff 100644 --- a/firmware/CMakeLists.txt +++ b/firmware/CMakeLists.txt @@ -23,6 +23,10 @@ add_compile_options(-Wall) add_compile_options($<$:-std=c++17>) +if(PICO_BOARD STREQUAL "pico") +add_compile_definitions(GPIO_VALID_PINS_BASE=0b00011100011111111111111111111111) +endif() + add_executable(remapper src/main.cc diff --git a/firmware/src/boards/feather_host.h b/firmware/src/boards/feather_host.h index 79e099e..1d1b871 100644 --- a/firmware/src/boards/feather_host.h +++ b/firmware/src/boards/feather_host.h @@ -8,6 +8,8 @@ #define FEATHER_HOST_BOARD +#define GPIO_VALID_PINS_BASE 0b00111111000000001101111111111111 + // On some samples, the xosc can take longer to stabilize than is usual #ifndef PICO_XOSC_STARTUP_DELAY_MULTIPLIER #define PICO_XOSC_STARTUP_DELAY_MULTIPLIER 64 diff --git a/firmware/src/boards/remapper.h b/firmware/src/boards/remapper.h index cde5212..88d430d 100644 --- a/firmware/src/boards/remapper.h +++ b/firmware/src/boards/remapper.h @@ -11,6 +11,8 @@ #define PIN_SWDCLK 28 #define PIN_SWDIO 27 +#define GPIO_VALID_PINS_BASE 0b00000000000000000000000000000000 + // --- FLASH --- #define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1 diff --git a/firmware/src/globals.cc b/firmware/src/globals.cc index 8694406..df6e841 100644 --- a/firmware/src/globals.cc +++ b/firmware/src/globals.cc @@ -40,3 +40,5 @@ std::vector expressions[NEXPRESSIONS]; bool monitor_enabled = false; const our_descriptor_def_t* our_descriptor; + +uint8_t gpio_out_state[4] = { 0 }; diff --git a/firmware/src/globals.h b/firmware/src/globals.h index 64cab51..ce8c7fc 100644 --- a/firmware/src/globals.h +++ b/firmware/src/globals.h @@ -51,4 +51,6 @@ extern bool monitor_enabled; extern const our_descriptor_def_t* our_descriptor; +extern uint8_t gpio_out_state[4]; + #endif diff --git a/firmware/src/main.cc b/firmware/src/main.cc index 313cee7..ea64b73 100644 --- a/firmware/src/main.cc +++ b/firmware/src/main.cc @@ -26,16 +26,13 @@ #define CONFIG_OFFSET_IN_FLASH (PICO_FLASH_SIZE_BYTES - PERSISTED_CONFIG_SIZE) #define FLASH_CONFIG_IN_MEMORY (((uint8_t*) XIP_BASE) + CONFIG_OFFSET_IN_FLASH) -#define GPIO_PIN_FIRST 2 -#define GPIO_PIN_LAST 9 -#define GPIO_PIN_MASK ((1 << (GPIO_PIN_LAST + 1)) - (1 << GPIO_PIN_FIRST)) - -#define GPIO_USAGE_PAGE 0xFFF40000 - uint64_t next_print = 0; mutex_t mutexes[(uint8_t) MutexId::N]; +uint32_t gpio_valid_pins_mask = 0; +uint32_t gpio_in_mask = 0; +uint32_t gpio_out_mask = 0; uint32_t prev_gpio_state = 0; uint64_t last_gpio_change[32] = { 0 }; @@ -59,17 +56,29 @@ bool do_send_report(uint8_t interface, const uint8_t* report_with_id, uint8_t le } void gpio_pins_init() { - for (uint8_t i = GPIO_PIN_FIRST; i <= GPIO_PIN_LAST; i++) { - gpio_init(i); - gpio_pull_up(i); + gpio_valid_pins_mask = get_gpio_valid_pins_mask(); + gpio_init_mask(gpio_valid_pins_mask); +} + +void set_gpio_inout_masks(uint32_t in_mask, uint32_t out_mask) { + // if some pin appears as both input and output, input wins + gpio_out_mask = (out_mask & ~in_mask) & gpio_valid_pins_mask; + // we treat all pins except the output ones as input so that the monitor works + gpio_in_mask = gpio_valid_pins_mask & ~gpio_out_mask; + gpio_set_dir_masked(gpio_valid_pins_mask, gpio_out_mask); + for (uint8_t i = 0; i <= 29; i++) { + uint32_t bit = 1 << i; + if (gpio_valid_pins_mask & bit) { + gpio_set_pulls(i, gpio_in_mask & bit, false); + } } } bool read_gpio(uint64_t now) { - uint32_t gpio_state = gpio_get_all() & GPIO_PIN_MASK; + uint32_t gpio_state = gpio_get_all() & gpio_in_mask; uint32_t changed = prev_gpio_state ^ gpio_state; if (changed != 0) { - for (uint8_t i = GPIO_PIN_FIRST; i <= GPIO_PIN_LAST; i++) { + for (uint8_t i = 0; i <= 29; i++) { uint32_t bit = 1 << i; if (changed & bit) { if (last_gpio_change[i] + gpio_debounce_time <= now) { @@ -92,6 +101,12 @@ bool read_gpio(uint64_t now) { return changed != 0; } +void write_gpio() { + uint32_t value = gpio_out_state[0] | (gpio_out_state[1] << 8) | (gpio_out_state[2] << 16) | (gpio_out_state[3] << 24); + gpio_put_masked(gpio_out_mask, value); + memset(gpio_out_state, 0, sizeof(gpio_out_state)); +} + void do_persist_config(uint8_t* buffer) { #if !PICO_COPY_TO_RAM uint32_t ints = save_and_disable_interrupts(); @@ -175,6 +190,7 @@ int main() { activity_led_on(); } process_mapping(true); + write_gpio(); } tud_task(); if (config_updated) { diff --git a/firmware/src/pico_debug/swd.c b/firmware/src/pico_debug/swd.c index 2da5f66..9a89675 100644 --- a/firmware/src/pico_debug/swd.c +++ b/firmware/src/pico_debug/swd.c @@ -11,14 +11,6 @@ #include "swd.h" -#ifndef PIN_SWDCLK -#define PIN_SWDCLK 2 -#endif - -#ifndef PIN_SWDIO -#define PIN_SWDIO 3 -#endif - #define OUT 1 #define IN 0 diff --git a/firmware/src/pico_debug/swd.h b/firmware/src/pico_debug/swd.h index 29b404c..8a234a6 100644 --- a/firmware/src/pico_debug/swd.h +++ b/firmware/src/pico_debug/swd.h @@ -12,6 +12,14 @@ #ifndef __SWD_H #define __SWD_H +#ifndef PIN_SWDCLK +#define PIN_SWDCLK 2 +#endif + +#ifndef PIN_SWDIO +#define PIN_SWDIO 3 +#endif + #define SWD_OK 0 #define SWD_WAIT 1 #define SWD_FAULT 2 diff --git a/firmware/src/platform.h b/firmware/src/platform.h index 16921b6..e27b41a 100644 --- a/firmware/src/platform.h +++ b/firmware/src/platform.h @@ -18,4 +18,7 @@ void my_mutex_exit(MutexId id); uint64_t get_time(); uint64_t get_unique_id(); +uint32_t get_gpio_valid_pins_mask(); +void set_gpio_inout_masks(uint32_t in_mask, uint32_t out_mask); + #endif diff --git a/firmware/src/remapper.cc b/firmware/src/remapper.cc index 92e9741..b7c04c9 100644 --- a/firmware/src/remapper.cc +++ b/firmware/src/remapper.cc @@ -295,6 +295,8 @@ void set_mapping_from_config() { used_state_slots = 0; usage_state_ptr.clear(); memset(input_state, 0, sizeof(input_state)); + uint32_t gpio_in_mask_ = 0; + uint32_t gpio_out_mask_ = 0; for (auto const& mapping : config_mappings) { uint8_t layer_mask = mapping.layer_mask; @@ -311,6 +313,16 @@ void set_mapping_from_config() { } } + if ((mapping.target_usage & 0xFFFF0000) == GPIO_USAGE_PAGE) { + uint16_t pin = mapping.target_usage & 0xFFFF; + gpio_out_mask_ |= 1 << pin; + } + + if ((mapping.source_usage & 0xFFFF0000) == GPIO_USAGE_PAGE) { + uint16_t pin = mapping.source_usage & 0xFFFF; + gpio_in_mask_ |= 1 << pin; + } + if (assign_state_slot(mapping.source_usage)) { reverse_mapping_map[mapping.target_usage].push_back((map_source_t){ .usage = mapping.source_usage, @@ -328,6 +340,12 @@ void set_mapping_from_config() { for (auto const& elem : expressions[expr]) { if (elem.op == Op::PUSH_USAGE) { mapped_on_layers[elem.val] |= layer_mask; + + // if a GPIO pin usage appears in an expression, it's an "in" pin + if ((elem.val & 0xFFFF0000) == GPIO_USAGE_PAGE) { + uint16_t pin = elem.val & 0xFFFF; + gpio_in_mask_ |= 1 << pin; + } } } } @@ -427,16 +445,25 @@ void set_mapping_from_config() { .target = target, .sources = sources, }; - auto search = our_usages_flat.find(target); - if (search != our_usages_flat.end()) { - const usage_def_t& our_usage = search->second; + if ((target & 0xFFFF0000) == GPIO_USAGE_PAGE) { rev_map.our_usages.push_back((out_usage_def_t){ - .data = reports[our_usage.report_id], - .len = report_sizes[our_usage.report_id], - .size = our_usage.size, - .bitpos = our_usage.bitpos, + .data = gpio_out_state, + .len = sizeof(gpio_out_state), + .size = 1, + .bitpos = (uint16_t) (target & 0xFFFF), }); - rev_map.is_relative = our_usage.is_relative; + } else { + auto search = our_usages_flat.find(target); + if (search != our_usages_flat.end()) { + const usage_def_t& our_usage = search->second; + rev_map.our_usages.push_back((out_usage_def_t){ + .data = reports[our_usage.report_id], + .len = report_sizes[our_usage.report_id], + .size = our_usage.size, + .bitpos = our_usage.bitpos, + }); + rev_map.is_relative = our_usage.is_relative; + } } if ((target & 0xFFFF0000) == MACRO_USAGE_PAGE) { reverse_mapping_macros.push_back(rev_map); @@ -447,6 +474,7 @@ void set_mapping_from_config() { } } + set_gpio_inout_masks(gpio_in_mask_, gpio_out_mask_); update_their_descriptor_derivates(); } diff --git a/firmware/src/remapper.h b/firmware/src/remapper.h index f4d602c..4bf6a19 100644 --- a/firmware/src/remapper.h +++ b/firmware/src/remapper.h @@ -3,6 +3,8 @@ #define OUR_OUT_INTERFACE 0xFFFF +#define GPIO_USAGE_PAGE 0xFFF40000 + typedef bool (*send_report_t)(uint8_t interface, const uint8_t* report_with_id, uint8_t len); void set_mapping_from_config(); diff --git a/firmware/src/remapper_dual_a.cc b/firmware/src/remapper_dual_a.cc index f348a7b..b394fb0 100644 --- a/firmware/src/remapper_dual_a.cc +++ b/firmware/src/remapper_dual_a.cc @@ -82,6 +82,19 @@ void extra_init() { serial_init(); } +uint32_t get_gpio_valid_pins_mask() { + return GPIO_VALID_PINS_BASE & ~( + (1 << PICO_DEFAULT_UART_TX_PIN) | + (1 << PICO_DEFAULT_UART_RX_PIN) | + (1 << PIN_SWDIO) | + (1 << PIN_SWDCLK) | + (1 << SERIAL_TX_PIN) | + (1 << SERIAL_RX_PIN) | + (1 << SERIAL_CTS_PIN) | + (1 << SERIAL_RTS_PIN) + ); +} + void read_report(bool* new_report, bool* tick) { *new_report = serial_read(serial_callback); *tick = get_and_clear_tick_pending(); diff --git a/firmware/src/remapper_serial.cc b/firmware/src/remapper_serial.cc index 553c916..8fa390e 100644 --- a/firmware/src/remapper_serial.cc +++ b/firmware/src/remapper_serial.cc @@ -63,6 +63,14 @@ void extra_init() { parse_descriptor(FAKE_VID, FAKE_PID, fake_descriptor, sizeof(fake_descriptor), FAKE_INTERFACE); } +uint32_t get_gpio_valid_pins_mask() { + return GPIO_VALID_PINS_BASE & ~( + (1 << PICO_DEFAULT_UART_TX_PIN) | + (1 << PICO_DEFAULT_UART_RX_PIN) | + (1 << SERIAL_MOUSE_RX_PIN) + ); +} + void read_report(bool* new_report, bool* tick) { *tick = get_and_clear_tick_pending(); *new_report = false; diff --git a/firmware/src/remapper_single.cc b/firmware/src/remapper_single.cc index 28a537d..0f214a6 100644 --- a/firmware/src/remapper_single.cc +++ b/firmware/src/remapper_single.cc @@ -17,6 +17,15 @@ void extra_init() { tuh_configure(BOARD_TUH_RHPORT, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &pio_cfg); } +uint32_t get_gpio_valid_pins_mask() { + return GPIO_VALID_PINS_BASE & ~( + (1 << PICO_DEFAULT_UART_TX_PIN) | + (1 << PICO_DEFAULT_UART_RX_PIN) | + (1 << PICO_DEFAULT_PIO_USB_DP_PIN) | + (1 << (PICO_DEFAULT_PIO_USB_DP_PIN + 1)) + ); +} + static bool reports_received; void read_report(bool* new_report, bool* tick) { diff --git a/firmware/src/serial.cc b/firmware/src/serial.cc index 438024d..bf0e67c 100644 --- a/firmware/src/serial.cc +++ b/firmware/src/serial.cc @@ -10,22 +10,6 @@ #define SERIAL_UART uart1 #define SERIAL_BAUDRATE 4000000 -#ifdef HID_REMAPPER_BOARD - -#define SERIAL_TX_PIN 24 -#define SERIAL_RX_PIN 25 -#define SERIAL_CTS_PIN 26 -#define SERIAL_RTS_PIN 23 - -#else - -#define SERIAL_TX_PIN 20 -#define SERIAL_RX_PIN 21 -#define SERIAL_CTS_PIN 26 -#define SERIAL_RTS_PIN 27 - -#endif - #define BUFFER_SIZE 512 static char outgoing_buffer[BUFFER_SIZE]; static uint16_t buf_head = 0; diff --git a/firmware/src/serial.h b/firmware/src/serial.h index 5b58072..1bbfcbf 100644 --- a/firmware/src/serial.h +++ b/firmware/src/serial.h @@ -5,6 +5,22 @@ #define SERIAL_MAX_PAYLOAD_SIZE 512 +#ifdef HID_REMAPPER_BOARD + +#define SERIAL_TX_PIN 24 +#define SERIAL_RX_PIN 25 +#define SERIAL_CTS_PIN 26 +#define SERIAL_RTS_PIN 23 + +#else + +#define SERIAL_TX_PIN 20 +#define SERIAL_RX_PIN 21 +#define SERIAL_CTS_PIN 26 +#define SERIAL_RTS_PIN 27 + +#endif + typedef bool (*msg_recv_cb_t)(const uint8_t* data, uint16_t len); void serial_init();