diff --git a/CMakeLists.txt b/CMakeLists.txt index ce4a48c..bfd4016 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,29 +1,42 @@ cmake_minimum_required(VERSION 3.6) +## Version Configuration set(VERSION_MAJOR 00) -set(VERSION_MINOR 160) +set(VERSION_MINOR 161) +## Release Type Selection +option(DH_DEBUG "Build a debug version" OFF) + +## Hardware Configuration +set(DP_PIN_DEFAULT 14 CACHE STRING "Default USB D+ Pin Number") +set(PIO_USE_TINYUSB 1 CACHE STRING "Make TinyUSB Manage the PIO USB Port") +set(PICO_BOARD "pico") + +## Pico SDK Configuration set(PICO_SDK_FETCH_FROM_GIT off) -set(PICO_BOARD=pico) set(PICO_SDK_PATH ${CMAKE_CURRENT_LIST_DIR}/pico-sdk) - +set(SRC_DIR ${CMAKE_CURRENT_LIST_DIR}/src) include(pico_sdk_import.cmake) -set(CMAKE_C_FLAGS "-Ofast -Wall -mcpu=cortex-m0plus -mtune=cortex-m0plus -fstack-usage") - -set(PICO_COPY_TO_RAM 1) +## Project Setup project(deskhop_project C CXX ASM) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) +set(PICO_COPY_TO_RAM 1) +## Compiler Flags +set(CMAKE_C_FLAGS "-Ofast -Wall -mcpu=cortex-m0plus -mtune=cortex-m0plus -fstack-usage") + +## Initialize Pico SDK pico_sdk_init() +## PIO USB Library Setup set(PICO_PIO_USB_DIR ${CMAKE_CURRENT_LIST_DIR}/Pico-PIO-USB) add_library(Pico-PIO-USB STATIC - ${PICO_PIO_USB_DIR}/src/pio_usb.c - ${PICO_PIO_USB_DIR}/src/pio_usb_host.c - ${PICO_PIO_USB_DIR}/src/usb_crc.c + ${PICO_PIO_USB_DIR}/src/pio_usb.c + ${PICO_PIO_USB_DIR}/src/pio_usb_host.c + ${PICO_PIO_USB_DIR}/src/usb_crc.c ) pico_generate_pio_header(Pico-PIO-USB ${PICO_PIO_USB_DIR}/src/usb_tx.pio) pico_generate_pio_header(Pico-PIO-USB ${PICO_PIO_USB_DIR}/src/usb_rx.pio) @@ -36,33 +49,36 @@ target_link_libraries(Pico-PIO-USB PRIVATE ) target_include_directories(Pico-PIO-USB PRIVATE ${PICO_PIO_USB_DIR}) +## Source Files set(COMMON_SOURCES - ${CMAKE_CURRENT_LIST_DIR}/src/usb_descriptors.c - ${CMAKE_CURRENT_LIST_DIR}/src/defaults.c - ${CMAKE_CURRENT_LIST_DIR}/src/constants.c - ${CMAKE_CURRENT_LIST_DIR}/src/protocol.c - ${CMAKE_CURRENT_LIST_DIR}/src/hid_parser.c - ${CMAKE_CURRENT_LIST_DIR}/src/hid_report.c - ${CMAKE_CURRENT_LIST_DIR}/src/utils.c - ${CMAKE_CURRENT_LIST_DIR}/src/handlers.c - ${CMAKE_CURRENT_LIST_DIR}/src/setup.c - ${CMAKE_CURRENT_LIST_DIR}/src/keyboard.c - ${CMAKE_CURRENT_LIST_DIR}/src/mouse.c - ${CMAKE_CURRENT_LIST_DIR}/src/tasks.c - ${CMAKE_CURRENT_LIST_DIR}/src/led.c - ${CMAKE_CURRENT_LIST_DIR}/src/uart.c - ${CMAKE_CURRENT_LIST_DIR}/src/usb.c - ${CMAKE_CURRENT_LIST_DIR}/src/main.c - ${CMAKE_CURRENT_LIST_DIR}/src/ramdisk.c - ${PICO_TINYUSB_PATH}/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c - ${PICO_TINYUSB_PATH}/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c + ${SRC_DIR}/usb_descriptors.c + ${SRC_DIR}/defaults.c + ${SRC_DIR}/constants.c + ${SRC_DIR}/protocol.c + ${SRC_DIR}/hid_parser.c + ${SRC_DIR}/hid_report.c + ${SRC_DIR}/utils.c + ${SRC_DIR}/handlers.c + ${SRC_DIR}/setup.c + ${SRC_DIR}/keyboard.c + ${SRC_DIR}/mouse.c + ${SRC_DIR}/tasks.c + ${SRC_DIR}/led.c + ${SRC_DIR}/uart.c + ${SRC_DIR}/usb.c + ${SRC_DIR}/main.c + ${SRC_DIR}/ramdisk.c + ${PICO_TINYUSB_PATH}/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c + ${PICO_TINYUSB_PATH}/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c ) +## Include Directories set(COMMON_INCLUDES - ${CMAKE_CURRENT_LIST_DIR}/src/include - ${PICO_PIO_USB_DIR}/src + ${SRC_DIR}/include + ${PICO_PIO_USB_DIR}/src ) +## Library Dependencies set(COMMON_LINK_LIBRARIES pico_stdlib hardware_flash @@ -76,12 +92,14 @@ set(COMMON_LINK_LIBRARIES pico_multicore Pico-PIO-USB ) - set(binary deskhop) +## Disk Image Configuration +# This assembles disk.S, then updates the elf section in post-build +# With the disk FAT image binary in /disk/disk.img + set(DISK_ASM "${CMAKE_CURRENT_LIST_DIR}/disk/disk.S") set(DISK_BIN "${CMAKE_CURRENT_LIST_DIR}/disk/disk.img") - set_property(SOURCE ${DISK_ASM} APPEND PROPERTY COMPILE_OPTIONS "-x" "assembler-with-cpp") add_executable(${binary} ${DISK_ASM}) @@ -89,21 +107,28 @@ add_executable(${binary} ${DISK_ASM}) target_sources(${binary} PUBLIC ${COMMON_SOURCES}) target_compile_definitions(${binary} PRIVATE - PIO_USB_USE_TINYUSB=1 - PIO_USB_DP_PIN_DEFAULT=14 - # Uncomment to enable debug uart: - # DH_DEBUG=1 + PIO_USB_USE_TINYUSB=${PIO_USE_TINYUSB} + PIO_USB_DP_PIN_DEFAULT=${DP_PIN_DEFAULT} __disk_file_path__="${DISK_BIN}" ) + +## Support building a debug version +if (DH_DEBUG) + add_definitions(-DDH_DEBUG) +endif() target_include_directories(${binary} PUBLIC ${COMMON_INCLUDES}) target_link_libraries(${binary} PUBLIC ${COMMON_LINK_LIBRARIES}) +## Configure Pico Library pico_enable_stdio_usb(${binary} 0) pico_enable_stdio_uart(${binary} 0) +pico_set_linker_script(${binary} ${CMAKE_SOURCE_DIR}/memory_map.ld) +## Build other file formats as well pico_add_extra_outputs(${binary}) +## Post-Build Commands add_custom_command( TARGET ${binary} POST_BUILD COMMAND python3 ${CMAKE_SOURCE_DIR}/tools/crc32.py ${binary}.bin ${binary}.crc ${VERSION_MAJOR}${VERSION_MINOR} @@ -113,9 +138,9 @@ add_custom_command( COMMENT "Update CRC32 section to match the actual binary" ) +## Linker Options target_link_options(${binary} PRIVATE -Xlinker --print-memory-usage ) -pico_set_linker_script(${binary} ${CMAKE_SOURCE_DIR}/memory_map.ld) diff --git a/README.md b/README.md index 3432327..73f3dce 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,9 @@ All I wanted was a way to use a keyboard shortcut to quickly switch outputs, pai - Full Galvanic isolation between your outputs - Works with Linux, macOS and Windows +![Image](img/oshw.svg){width=240} +[Proudly certified](https://certification.oshwa.org/de000149.html) by the Open Source Hardware Association (oshwa.org) + ------ ## How it works @@ -50,6 +53,9 @@ It also remembers the LED state for each computer, so you can pick up exactly ho ![Image](img/demo-typing.gif) +## User Manual +To help you set up, configure and program the board available [read the manual provided here](user-manual.pdf). + ## How to build To avoid version mismatch and reported path issues when building, as well as to save you from having to download a large SDK, the project now bundles minimal pico sdk and tinyusb. @@ -208,19 +214,20 @@ The standard process to do that is using isopropyl alcohol and an old toothbrush ## Usage guide -### Keyboard shortcuts - (fw versions 0.64 +) +### Keyboard shortcuts - (fw versions 0.68+) _Config_ - ~~```Left Shift```~~ ```Left Ctrl + Right Shift + C + O``` - enter config mode - ```Right Shift + F12 + D``` - remove flash config - ```Right Shift + F12 + Y``` - save screen switch offset -- ```Right Shift + F12 + S``` - turn on/off screensaver option _Usage_ - ```Right CTRL + Right ALT``` - Toggle slower mouse mode - ```Right CTRL + K``` - Lock/Unlock mouse desktop switching - ```Right CTRL + L``` - Lock both outputs at once (set output OS before, see shortcuts below) -- ~~```Left Shift```~~ ```Left Ctrl + Right Shift + G``` - Toggle gaming mode (lock to screen, act as standard mouse) +- ~~```Left Shift```~~ ```Left CTRL + Right Shift + G``` - Toggle gaming mode (lock to screen, act as standard mouse) +- ```Left CTRL + Right Shift + S``` - Enable screensaver +- ```Left CTRL + Right Shift + X``` - Disable screensaver - ```Left CTRL + Caps Lock``` - Switch between outputs Note: some keyboards don't send both shifts at the same time properly, that's why the shortcut was changed - to work for everyone. Apologies for the confusion. @@ -316,6 +323,7 @@ This still doesn't guarantee anything, but I believe it makes a reasonable set o *I'm not selling anything, this is just a personal, non-commercial hobby project.* [UPDATE] It seems you can order it in QTY of 1 (for either PCB, assembled PCB or a fully assembled device) from [Elecrow if you follow this link](https://www.elecrow.com/deskhop-fast-desktop-switching.html) +As reported by users, your **board will arrive blank** and you have to write the firmware yourself. [UPDATE2] - I never asked Elecrow for anything, but a couple of days ago they offered to sponsor the project with a small budget that will be used for future board prototyping. Since my goal is to create a better board with more than 2 outputs etc, I believe prototyping services might be beneficial to the project. diff --git a/img/oshw.svg b/img/oshw.svg new file mode 100644 index 0000000..2339976 --- /dev/null +++ b/img/oshw.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + DE000149 + + diff --git a/src/handlers.c b/src/handlers.c index 307a4f0..838ea6a 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -39,6 +39,12 @@ void _get_border_position(device_t *state, border_size_t *border) { border->top = state->pointer_y; } +void _screensaver_set(device_t *state, bool value) { + if (CURRENT_BOARD_IS_ACTIVE_OUTPUT) + state->config.output[BOARD_ROLE].screensaver.mode = value; + else + send_value(value, SCREENSAVER_MSG); +}; /* This key combo records switch y top coordinate for different-size monitors */ void screen_border_hotkey_handler(device_t *state, hid_keyboard_report_t *report) { @@ -115,6 +121,15 @@ void mouse_zoom_hotkey_handler(device_t *state, hid_keyboard_report_t *report) { send_value(state->mouse_zoom, MOUSE_ZOOM_MSG); }; +/* When pressed, enables the screensaver on active output */ +void enable_screensaver_hotkey_handler(device_t *state, hid_keyboard_report_t *report) { + _screensaver_set(state, true); +} + +/* When pressed, disables the screensaver on active output */ +void disable_screensaver_hotkey_handler(device_t *state, hid_keyboard_report_t *report) { + _screensaver_set(state, false); +} /* Put the device into a special configuration mode */ void config_enable_hotkey_handler(device_t *state, hid_keyboard_report_t *report) { @@ -209,6 +224,11 @@ void handle_wipe_config_msg(uart_packet_t *packet, device_t *state) { load_config(state); } +/* Update screensaver state after received message */ +void handle_screensaver_msg(uart_packet_t *packet, device_t *state) { + state->config.output[BOARD_ROLE].screensaver.mode = packet->data[0]; +} + /* Process consumer control message */ void handle_consumer_control_msg(uart_packet_t *packet, device_t *state) { queue_cc_packet(packet->data, state); @@ -254,9 +274,9 @@ void handle_api_msgs(uart_packet_t *packet, device_t *state) { memcpy(ptr, &packet->data[1], map->len); } else if (packet->type == GET_VAL_MSG) { - uart_packet_t response = {.type=GET_VAL_MSG, .data={[0] = value_idx}}; - memcpy(&response.data[1], ptr, map->len); - queue_cfg_packet(&response, state); + uart_packet_t response = {.type=GET_VAL_MSG, .data={[0] = value_idx}}; + memcpy(&response.data[1], ptr, map->len); + queue_cfg_packet(&response, state); } /* With each GET/SET message, we reset the configuration mode timeout */ diff --git a/src/include/main.h b/src/include/main.h index a44d844..bb72223 100644 --- a/src/include/main.h +++ b/src/include/main.h @@ -123,6 +123,7 @@ enum packet_type_e { SYNC_BORDERS_MSG = 8, FLASH_LED_MSG = 9, WIPE_CONFIG_MSG = 10, + SCREENSAVER_MSG = 11, HEARTBEAT_MSG = 12, GAMING_MODE_MSG = 13, CONSUMER_CONTROL_MSG = 14, @@ -540,6 +541,8 @@ void screenlock_hotkey_handler(device_t *, hid_keyboard_report_t *); void output_config_hotkey_handler(device_t *, hid_keyboard_report_t *); void wipe_config_hotkey_handler(device_t *, hid_keyboard_report_t *); void config_enable_hotkey_handler(device_t *, hid_keyboard_report_t *); +void enable_screensaver_hotkey_handler(device_t *, hid_keyboard_report_t *); +void disable_screensaver_hotkey_handler(device_t *, hid_keyboard_report_t *); void handle_keyboard_uart_msg(uart_packet_t *, device_t *); void handle_mouse_abs_uart_msg(uart_packet_t *, device_t *); @@ -563,6 +566,7 @@ void handle_proxy_msg(uart_packet_t *, device_t *); void handle_api_msgs(uart_packet_t *, device_t *); void handle_api_read_all_msg(uart_packet_t *, device_t *); void handle_toggle_gaming_msg(uart_packet_t *, device_t *); +void handle_screensaver_msg(uart_packet_t *, device_t *); void switch_output(device_t *, uint8_t); diff --git a/src/include/usb_descriptors.h b/src/include/usb_descriptors.h index 73ef67e..8f4acbe 100644 --- a/src/include/usb_descriptors.h +++ b/src/include/usb_descriptors.h @@ -70,15 +70,11 @@ HID_LOGICAL_MIN ( 0 ) ,\ HID_LOGICAL_MAX ( 1 ) ,\ \ - /* Left, Right, Middle, Backward, Forward buttons */ \ - HID_REPORT_COUNT( 5 ) ,\ + /* Left, Right, Mid, Back, Forward buttons + 3 extra */ \ + HID_REPORT_COUNT( 8 ) ,\ HID_REPORT_SIZE ( 1 ) ,\ HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ \ - /* 3 bit padding */ \ - HID_REPORT_COUNT( 1 ) ,\ - HID_REPORT_SIZE ( 3 ) ,\ - HID_INPUT ( HID_CONSTANT ) ,\ HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ \ /* X, Y position [MOUSE_MIN, 32767] */ \ diff --git a/src/keyboard.c b/src/keyboard.c index aea00e6..071ffca 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -58,6 +58,20 @@ hotkey_combo_t hotkeys[] = { .acknowledge = true, .action_handler = &toggle_gaming_mode_handler}, + /* Enable screensaver for active output */ + {.modifier = KEYBOARD_MODIFIER_LEFTCTRL | KEYBOARD_MODIFIER_RIGHTSHIFT, + .keys = {HID_KEY_S}, + .key_count = 1, + .acknowledge = true, + .action_handler = &enable_screensaver_hotkey_handler}, + + /* Disable screensaver for active output */ + {.modifier = KEYBOARD_MODIFIER_LEFTCTRL | KEYBOARD_MODIFIER_RIGHTSHIFT, + .keys = {HID_KEY_X}, + .key_count = 1, + .acknowledge = true, + .action_handler = &disable_screensaver_hotkey_handler}, + /* Erase stored config */ {.modifier = KEYBOARD_MODIFIER_RIGHTSHIFT, .keys = {HID_KEY_F12, HID_KEY_D}, diff --git a/src/tasks.c b/src/tasks.c index 6790c0f..c802da1 100644 --- a/src/tasks.c +++ b/src/tasks.c @@ -133,9 +133,11 @@ void heartbeat_output_task(device_t *state) { blink_led(state); } +#ifdef DH_DEBUG /* Holding the button invokes bootsel firmware upgrade */ if (is_bootsel_pressed()) reset_usb_boot(1 << PICO_DEFAULT_LED_PIN, 0); +#endif uart_packet_t packet = { .type = HEARTBEAT_MSG, diff --git a/src/uart.c b/src/uart.c index 134cb21..a2c7e6b 100644 --- a/src/uart.c +++ b/src/uart.c @@ -78,6 +78,7 @@ const uart_handler_t uart_handler[] = { {.type = FLASH_LED_MSG, .handler = handle_flash_led_msg}, {.type = GAMING_MODE_MSG, .handler = handle_toggle_gaming_msg}, {.type = CONSUMER_CONTROL_MSG, .handler = handle_consumer_control_msg}, + {.type = SCREENSAVER_MSG, .handler = handle_screensaver_msg}, /* Config */ {.type = WIPE_CONFIG_MSG, .handler = handle_wipe_config_msg}, diff --git a/user-manual.pdf b/user-manual.pdf new file mode 100644 index 0000000..d2586d5 Binary files /dev/null and b/user-manual.pdf differ