Skip to content

Commit

Permalink
GPIO outputs
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
jfedor2 committed Nov 7, 2023
1 parent 51107fe commit a24ce02
Show file tree
Hide file tree
Showing 18 changed files with 189 additions and 43 deletions.
52 changes: 52 additions & 0 deletions config-tool-web/usages.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
Expand All @@ -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' },
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions firmware-bluetooth/src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
4 changes: 4 additions & 0 deletions firmware/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ add_compile_options(-Wall)

add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-std=c++17>)

if(PICO_BOARD STREQUAL "pico")
add_compile_definitions(GPIO_VALID_PINS_BASE=0b00011100011111111111111111111111)
endif()


add_executable(remapper
src/main.cc
Expand Down
2 changes: 2 additions & 0 deletions firmware/src/boards/feather_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions firmware/src/boards/remapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions firmware/src/globals.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,5 @@ std::vector<expr_elem_t> expressions[NEXPRESSIONS];
bool monitor_enabled = false;

const our_descriptor_def_t* our_descriptor;

uint8_t gpio_out_state[4] = { 0 };
2 changes: 2 additions & 0 deletions firmware/src/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,6 @@ extern bool monitor_enabled;

extern const our_descriptor_def_t* our_descriptor;

extern uint8_t gpio_out_state[4];

#endif
38 changes: 27 additions & 11 deletions firmware/src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 };

Expand All @@ -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) {
Expand All @@ -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();
Expand Down Expand Up @@ -175,6 +190,7 @@ int main() {
activity_led_on();
}
process_mapping(true);
write_gpio();
}
tud_task();
if (config_updated) {
Expand Down
8 changes: 0 additions & 8 deletions firmware/src/pico_debug/swd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 8 additions & 0 deletions firmware/src/pico_debug/swd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions firmware/src/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
44 changes: 36 additions & 8 deletions firmware/src/remapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -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;
}
}
}
}
Expand Down Expand Up @@ -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);
Expand All @@ -447,6 +474,7 @@ void set_mapping_from_config() {
}
}

set_gpio_inout_masks(gpio_in_mask_, gpio_out_mask_);
update_their_descriptor_derivates();
}

Expand Down
2 changes: 2 additions & 0 deletions firmware/src/remapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
13 changes: 13 additions & 0 deletions firmware/src/remapper_dual_a.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
8 changes: 8 additions & 0 deletions firmware/src/remapper_serial.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions firmware/src/remapper_single.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Loading

0 comments on commit a24ce02

Please sign in to comment.