diff --git a/.github/workflows/build-user-config.yml b/.github/workflows/build-user-config.yml index af57520bcd2..023f18bab5e 100644 --- a/.github/workflows/build-user-config.yml +++ b/.github/workflows/build-user-config.yml @@ -121,6 +121,7 @@ jobs: shell: sh -x {0} run: west build -s zmk/app -d "${{ env.build_dir }}" -b "${{ matrix.board }}" -- -DZMK_CONFIG=${{ env.base_dir }}/${{ inputs.config_path }} ${{ env.extra_cmake_args }} ${{ matrix.cmake-args }} +<<<<<<< HEAD - name: ${{ env.display_name }} Kconfig file run: | if [ -f "${{ env.build_dir }}/zephyr/.config" ] @@ -143,6 +144,16 @@ jobs: echo "No Devicetree output" fi if: ${{ !cancelled() }} +======= + - name: ${{ steps.variables.outputs.display-name }} DTS File + if: ${{ always() }} + run: | + if [ -f "build/zephyr/${{ matrix.board }}.dts.pre.tmp" ]; then cat -n build/zephyr/${{ matrix.board }}.dts.pre.tmp; fi + if [ -f "build/zephyr/zephyr.dts" ]; then cat -n build/zephyr/zephyr.dts; fi + + - name: ${{ steps.variables.outputs.display-name }} Kconfig file + run: grep -v -e "^#" -e "^$" build/zephyr/.config | sort +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 - name: Rename artifacts shell: sh -x {0} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 17be98de748..9781229824a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,8 +9,14 @@ on: paths: - ".github/workflows/build.yml" - "app/**" +<<<<<<< HEAD schedule: - cron: "22 4 * * *" +======= +# disabling auto build until fixing all build errors to prevent excessive emails +# schedule: +# - cron: '22 4 * * *' +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 jobs: build: @@ -24,7 +30,11 @@ jobs: include: ${{ fromJSON(needs.compile-matrix.outputs.include-list) }} steps: - name: Checkout +<<<<<<< HEAD uses: actions/checkout@v4 +======= + uses: actions/checkout@v3 +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 - name: Cache west modules uses: actions/cache@v4 env: @@ -178,7 +188,11 @@ jobs: core-include: ${{ steps.core-list.outputs.result }} steps: - name: Checkout +<<<<<<< HEAD uses: actions/checkout@v4 +======= + uses: actions/checkout@v3 +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 - name: Use Node.js uses: actions/setup-node@v4 with: @@ -207,7 +221,11 @@ jobs: boards-include: ${{ steps.boards-list.outputs.result }} steps: - name: Checkout +<<<<<<< HEAD uses: actions/checkout@v4 +======= + uses: actions/checkout@v3 +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 - name: Use Node.js uses: actions/setup-node@v4 with: @@ -335,7 +353,11 @@ jobs: organized-metadata: ${{ steps.organize-metadata.outputs.result }} steps: - name: Checkout +<<<<<<< HEAD uses: actions/checkout@v4 +======= + uses: actions/checkout@v3 +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 - name: Use Node.js uses: actions/setup-node@v4 with: diff --git a/.gitignore b/.gitignore index 4ddd08521ed..2bde7b3539f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,9 @@ /build *.DS_Store __pycache__ +<<<<<<< HEAD .python-version .venv +======= +*.~undo-tree~ +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 diff --git a/.vscode/settings.json b/.vscode/settings.json index 924d83b1f25..586917c9ee9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,9 @@ { "files.associations": { "*.overlay": "dts", - "*.keymap": "dts" + "*.keymap": "dts", + "usb_conn_state_changed.h": "c", + "ble_active_profile_changed.h": "c" }, "python.formatting.provider": "black", "[c]": { diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 6ef00311027..f36a50ac034 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -26,14 +26,27 @@ target_sources(app PRIVATE src/activity.c) target_sources(app PRIVATE src/behavior.c) target_sources(app PRIVATE src/kscan.c) target_sources(app PRIVATE src/matrix_transform.c) +target_sources(app PRIVATE src/mouse/key_listener.c) +target_sources(app PRIVATE src/mouse/main.c) +target_sources(app PRIVATE src/mouse/tick_listener.c) target_sources(app PRIVATE src/sensors.c) +target_sources(app PRIVATE src/point_device/main.c) +target_sources(app PRIVATE src/point_device/sliders.c) target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/wpm.c) target_sources(app PRIVATE src/event_manager.c) target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/ext_power_generic.c) target_sources(app PRIVATE src/events/activity_state_changed.c) target_sources(app PRIVATE src/events/position_state_changed.c) target_sources(app PRIVATE src/events/sensor_event.c) +<<<<<<< HEAD target_sources(app PRIVATE src/events/mouse_button_state_changed.c) +======= +target_sources(app PRIVATE src/events/pd_raw_event.c) +target_sources(app PRIVATE src/events/mouse_button_state_changed.c) +target_sources(app PRIVATE src/events/mouse_move_state_changed.c) +target_sources(app PRIVATE src/events/mouse_tick.c) +target_sources(app PRIVATE src/events/mouse_scroll_state_changed.c) +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/events/wpm_state_changed.c) target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/events/usb_conn_state_changed.c) target_sources(app PRIVATE src/behaviors/behavior_reset.c) @@ -55,10 +68,19 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) target_sources(app PRIVATE src/behaviors/behavior_to_layer.c) target_sources(app PRIVATE src/behaviors/behavior_transparent.c) target_sources(app PRIVATE src/behaviors/behavior_none.c) +<<<<<<< HEAD target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE app PRIVATE src/behaviors/behavior_sensor_rotate.c) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_VAR app PRIVATE src/behaviors/behavior_sensor_rotate_var.c) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON app PRIVATE src/behaviors/behavior_sensor_rotate_common.c) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_MOUSE_KEY_PRESS app PRIVATE src/behaviors/behavior_mouse_key_press.c) +======= + target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c) + target_sources(app PRIVATE src/behaviors/behavior_mouse_key_press.c) + target_sources(app PRIVATE src/behaviors/behavior_mouse_move.c) + target_sources(app PRIVATE src/behaviors/behavior_mouse_scroll.c) + target_sources(app PRIVATE src/behaviors/behavior_point_device_incremental.c) + target_sources(app PRIVATE src/behaviors/behavior_point_device_directional.c) +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 target_sources(app PRIVATE src/combo.c) target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c) target_sources(app PRIVATE src/behavior_queue.c) @@ -70,7 +92,14 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) target_sources(app PRIVATE src/events/layer_state_changed.c) target_sources(app PRIVATE src/events/modifiers_state_changed.c) target_sources(app PRIVATE src/events/keycode_state_changed.c) +<<<<<<< HEAD target_sources_ifdef(CONFIG_ZMK_HID_INDICATORS app PRIVATE src/hid_indicators.c) +======= + target_sources(app PRIVATE src/events/pd_scroll_state_changed.c) + target_sources(app PRIVATE src/events/pd_position_state_changed.c) + target_sources(app PRIVATE src/point_device/pd_listener.c) + target_sources(app PRIVATE src/point_device/trackballs.c) +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 if (CONFIG_ZMK_BLE) target_sources(app PRIVATE src/events/ble_active_profile_changed.c) diff --git a/app/Kconfig b/app/Kconfig index f90b1d2ab57..376d237063b 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -214,6 +214,10 @@ config ZMK_BLE_MOUSE_REPORT_QUEUE_SIZE int "Max number of mouse HID reports to queue for sending over BLE" default 20 +config ZMK_BLE_MOUSE_REPORT_QUEUE_SIZE + int "Max number of mouse HID reports to queue for sending over BLE" + default 20 + config ZMK_BLE_CLEAR_BONDS_ON_START bool "Configuration that clears all bond information from the keyboard on startup." default n @@ -381,13 +385,26 @@ endmenu menu "Mouse Options" +<<<<<<< HEAD config ZMK_MOUSE bool "Enable ZMK mouse emulation" default n +======= +rsource "src/mouse/Kconfig" +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 #Mouse Options endmenu +<<<<<<< HEAD +======= +menu "Point Device Options" + +rsource "src/point_device/Kconfig" + +endmenu + +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 menu "Power Management" config ZMK_BATTERY_REPORTING @@ -536,6 +553,7 @@ config ZMK_USB_LOGGING if ZMK_USB_LOGGING +<<<<<<< HEAD choice USB_CDC_ACM_LOG_LEVEL_CHOICE default USB_CDC_ACM_LOG_LEVEL_OFF endchoice @@ -543,6 +561,10 @@ endchoice choice USB_DRIVER_LOG_LEVEL_CHOICE default USB_DRIVER_LOG_LEVEL_OFF endchoice +======= +# config ZMK_LOG_LEVEL +# default 1 +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 # We do this to avoid log loop where logging to USB generates more log messages. diff --git a/app/boards/arm/nice_nano/CMakeLists.txt b/app/boards/arm/nice_nano/CMakeLists.txt new file mode 100644 index 00000000000..422dd57386e --- /dev/null +++ b/app/boards/arm/nice_nano/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (c) 2021 Darryl deHaan +# SPDX-License-Identifier: MIT +# + +if (CONFIG_NICE_NANO_POINTDEVICE) + add_subdirectory_ifdef(CONFIG_PINNACLE trackpad) + add_subdirectory_ifdef(CONFIG_PMW33XX trackball) + add_subdirectory_ifdef(CONFIG_PMW3360 trackball) + add_subdirectory_ifdef(CONFIG_PAW3395 trackball) + add_subdirectory_ifdef(CONFIG_PMW3610 trackball) +endif() \ No newline at end of file diff --git a/app/boards/arm/nice_nano/Kconfig.defconfig b/app/boards/arm/nice_nano/Kconfig.defconfig index 63102a571f9..4f4fef8747a 100644 --- a/app/boards/arm/nice_nano/Kconfig.defconfig +++ b/app/boards/arm/nice_nano/Kconfig.defconfig @@ -3,17 +3,59 @@ if BOARD_NICE_NANO || BOARD_NICE_NANO_V2 +<<<<<<< HEAD config BOARD +======= + config BOARD +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 default "nice_nano" -if USB_DEVICE_STACK + if USB_DEVICE_STACK +<<<<<<< HEAD config USB_NRFX default y +======= + config USB_NRFX + default y +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 -endif # USB_DEVICE_STACK + endif # USB_DEVICE_STACK +<<<<<<< HEAD config BT_CTLR default BT +======= + config BT_CTLR + default BT + + config ZMK_BLE + default y + + config ZMK_USB + default y + + # Role of the keyboard in split setup, default is master (i.e., central) + ## NOTE: this is a dedicated config option for nrfmacro board, so that all shields + ## using this board can share the some configuration. It's mainly used for controlling + ## which widget to show on different side of the keyboard + choice + prompt "Role of the keyboard" + help + Specify the role of the keyboard + + config NICE_NANO_SHIELD_MASTER + bool "master side, in charge of communication with host" + + config NICE_NANO_SHIELD_SLAVE + bool "slave side, acting as a peripheral to master side" + + endchoice + + # add point device + config NICE_NANO_POINTDEVICE + bool "add support for point device" + select SPI +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 endif # BOARD_NICE_NANO || BOARD_NICE_NANO_V2 diff --git a/app/boards/arm/nice_nano/nice_nano.dtsi b/app/boards/arm/nice_nano/nice_nano.dtsi index 81f10906b92..8722bae4d64 100644 --- a/app/boards/arm/nice_nano/nice_nano.dtsi +++ b/app/boards/arm/nice_nano/nice_nano.dtsi @@ -50,6 +50,10 @@ pinctrl-names = "default", "sleep"; }; +&spi0 { + compatible = "nordic,nrf-spim"; +}; + &uart0 { compatible = "nordic,nrf-uarte"; current-speed = <115200>; diff --git a/app/boards/arm/nice_nano/nice_nano.yaml b/app/boards/arm/nice_nano/nice_nano.yaml index 1c367324a3c..2484e8898f6 100644 --- a/app/boards/arm/nice_nano/nice_nano.yaml +++ b/app/boards/arm/nice_nano/nice_nano.yaml @@ -13,3 +13,5 @@ supported: - ieee802154 - pwm - watchdog + - spi + - i2c diff --git a/app/boards/arm/nice_nano/nice_nano_v2.dts b/app/boards/arm/nice_nano/nice_nano_v2.dts index c4f7a821c04..4c2a61697c9 100644 --- a/app/boards/arm/nice_nano/nice_nano_v2.dts +++ b/app/boards/arm/nice_nano/nice_nano_v2.dts @@ -23,3 +23,5 @@ compatible = "zmk,battery-nrf-vddh"; }; }; + +nice_nano_spi: &spi2 {}; \ No newline at end of file diff --git a/app/boards/arm/nice_nano/nice_nano_v2.yaml b/app/boards/arm/nice_nano/nice_nano_v2.yaml index d050ce993f9..170dab5cc8c 100644 --- a/app/boards/arm/nice_nano/nice_nano_v2.yaml +++ b/app/boards/arm/nice_nano/nice_nano_v2.yaml @@ -13,3 +13,5 @@ supported: - ieee802154 - pwm - watchdog + - spi + - i2c diff --git a/app/boards/arm/nice_nano/nice_nano_v2_defconfig b/app/boards/arm/nice_nano/nice_nano_v2_defconfig index 6b5044e5ef0..fb5d25a2cb4 100644 --- a/app/boards/arm/nice_nano/nice_nano_v2_defconfig +++ b/app/boards/arm/nice_nano/nice_nano_v2_defconfig @@ -23,5 +23,11 @@ CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y +<<<<<<< HEAD CONFIG_ZMK_BLE=y -CONFIG_ZMK_USB=y \ No newline at end of file +CONFIG_ZMK_USB=y +======= +# added from nrfmacro, not sure if needed for trackball +CONFIG_CLOCK_CONTROL_NRF=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 diff --git a/app/boards/arm/nice_nano/trackball/CMakeLists.txt b/app/boards/arm/nice_nano/trackball/CMakeLists.txt new file mode 100644 index 00000000000..d9449b5615c --- /dev/null +++ b/app/boards/arm/nice_nano/trackball/CMakeLists.txt @@ -0,0 +1,9 @@ +zephyr_library() +zephyr_library_sources_ifdef(CONFIG_PMW33XX trackball.c) +zephyr_library_sources_ifdef(CONFIG_PMW3360 trackball_new.c) +zephyr_library_sources_ifdef(CONFIG_PAW3395 trackball_new.c) +zephyr_library_sources_ifdef(CONFIG_PMW3610 trackball_new.c) + +zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include) +zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/drivers/sensor) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) diff --git a/app/boards/arm/nice_nano/trackball/trackball.c b/app/boards/arm/nice_nano/trackball/trackball.c new file mode 100644 index 00000000000..6ab91478b2f --- /dev/null +++ b/app/boards/arm/nice_nano/trackball/trackball.c @@ -0,0 +1,252 @@ +#define DT_DRV_COMPAT pixart_pmw33xx + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define SCROLL_DIV_FACTOR 5 +/* #define SCROLL_LAYER_INDEX 4 */ +#define SCROLL_LAYER_INDEX COND_CODE_0(DT_INST_NODE_HAS_PROP(0, scroll_layer), (255), \ + (DT_INST_PROP(0, scroll_layer))) + +#define CPI_DIVIDOR COND_CODE_0(DT_INST_NODE_HAS_PROP(0, cpi_dividor), (1), \ + (DT_INST_PROP(0, cpi_dividor))) + + +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ +// in us +static int64_t last_interrupt_time = 0; +static int64_t current_interrupt_time = 0; +static int64_t interrupt_interval = 0; +static int64_t handler_duration = 0; +static int64_t send_report_duration = 0; +static int64_t idle_interval = 0; +static int64_t time_buffer = 0; +/* #endif */ + +static int polling_count = 0; +static int max_poll_count = 0; +static int polling_interval = 0; +#define BLE_POLL_COUNT 20 +#define BLE_POLL_INTERVAL 15 // in ms +#define USB_POLL_COUNT 300 +#define USB_POLL_INTERVAL 1 // in ms + +// +static struct sensor_value dx, dy; + +const struct device *trackball = DEVICE_DT_GET(DT_DRV_INST(0)); + +LOG_MODULE_REGISTER(trackball, CONFIG_SENSOR_LOG_LEVEL); + + +/* update and send report */ +static int64_t trackball_update_handler(struct k_work *work) { +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + int64_t start_time = k_ticks_to_us_floor64(k_uptime_ticks()); +/* #endif */ + + // remaining scroll from last update + static int8_t scroll_ver_rem = 0, scroll_hor_rem = 0; + dx.val1 = dx.val1/CPI_DIVIDOR; + dy.val1 = dy.val1/CPI_DIVIDOR; + + // update report with latest position + zmk_hid_mouse_movement_set(0, 0); + zmk_hid_mouse_scroll_set(0, 0); + + const uint8_t layer = zmk_keymap_highest_layer_active(); + if (layer == SCROLL_LAYER_INDEX) { // lower + const int16_t total_hor = dx.val1 + scroll_hor_rem, total_ver = -(dy.val1 + scroll_ver_rem); + scroll_hor_rem = total_hor % SCROLL_DIV_FACTOR; + scroll_ver_rem = total_ver % SCROLL_DIV_FACTOR; + zmk_hid_mouse_scroll_update(total_hor / SCROLL_DIV_FACTOR, total_ver / SCROLL_DIV_FACTOR); + } else { + zmk_hid_mouse_movement_update(CLAMP(dx.val1, INT8_MIN, INT8_MAX), CLAMP(dy.val1, INT8_MIN, INT8_MAX)); + } + + // send the report to host + zmk_endpoints_send_mouse_report(); + +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + return start_time = k_ticks_to_us_floor64(k_uptime_ticks()) - start_time; +/* #else */ +/* return 0; */ +/* #endif */ +} + +// polling work +static void trackball_poll_handler(struct k_work *work) { +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + current_interrupt_time = k_ticks_to_us_floor64(k_uptime_ticks()); + interrupt_interval = current_interrupt_time - last_interrupt_time; + idle_interval = current_interrupt_time - time_buffer; +/* #endif */ + + + // fetch latest position from sensor + int ret = sensor_sample_fetch(trackball); + if (ret < 0) { + LOG_ERR("fetch: %d", ret); + return; + } + + // get the x, y delta + ret = sensor_channel_get(trackball, SENSOR_CHAN_POS_DX, &dx); + if (ret < 0) { + LOG_ERR("get dx: %d", ret); + return; + } + ret = sensor_channel_get(trackball, SENSOR_CHAN_POS_DY, &dy); + if (ret < 0) { + LOG_ERR("get dy: %d", ret); + return; + } + + if(dx.val1 != 0 || dy.val1 != 0) { + // process the updated position and send to host + /* k_work_submit_to_queue(zmk_mouse_work_q(), &trackball_update); */ +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + send_report_duration = trackball_update_handler(NULL); +/* #else */ +/* trackball_update_handler(NULL); */ +/* #endif */ + LOG_INF("Position updated: poll interval: %lld; send time: %lld ; new pos: %d %d",\ + interrupt_interval, send_report_duration, dx.val1, dy.val1); + } + +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + time_buffer = k_ticks_to_us_floor64(k_uptime_ticks()); + handler_duration = time_buffer - current_interrupt_time; + LOG_DBG("idle time: %lld ; handler time cost: %lld", \ + idle_interval, handler_duration); + + last_interrupt_time = current_interrupt_time; +} + +K_WORK_DEFINE(trackball_poll_work, &trackball_poll_handler); + +// polling timer +void trackball_timer_expiry(struct k_timer *timer); +void trackball_timer_stop(struct k_timer *timer); + +K_TIMER_DEFINE(trackball_timer, trackball_timer_expiry, trackball_timer_stop); + +// timer expiry function +void trackball_timer_expiry(struct k_timer *timer) { + // check whether reaching the polling count limit + if(polling_count < max_poll_count) { + // submit polling work to mouse work queue + k_work_submit_to_queue(zmk_mouse_work_q(), &trackball_poll_work); + + // update status + polling_count++; + } + else { + // stop timer + k_timer_stop(&trackball_timer); + } +} + +// timer stop function +void trackball_timer_stop(struct k_timer *timer) { + // reset status + polling_count = 0; + + // resume motion interrupt line + const struct pmw33xx_config *cfg = trackball->config; + if (gpio_pin_interrupt_configure(cfg->motswk_spec.port, cfg->motswk_spec.pin, GPIO_INT_LEVEL_ACTIVE)) { + LOG_WRN("Unable to set MOTSWK GPIO interrupt"); + } +} + + +// trigger handler +static void trackball_trigger_handler(const struct device *dev, const struct sensor_trigger *trig) { + struct pmw33xx_data *data = dev->data; + LOG_INF("I'm OLD trackball implementation"); + + // do not resume motion interrupt + data->resume_interrupt = false; + + // start the polling timer + k_timer_start(&trackball_timer, K_NO_WAIT, K_MSEC(polling_interval)); +} + +static int trackball_init() { + + struct sensor_trigger trigger = { + .type = SENSOR_TRIG_DATA_READY, + .chan = SENSOR_CHAN_ALL, + }; + printk("trackball"); + if (sensor_trigger_set(trackball, &trigger, trackball_trigger_handler) < 0) { + LOG_ERR("can't set trigger"); + return -EIO; + }; + + // init polling parameters + switch (zmk_endpoints_selected()) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ZMK_ENDPOINT_USB: { + max_poll_count = USB_POLL_COUNT; + polling_interval = USB_POLL_INTERVAL; + return 0; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB) */ + +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ZMK_ENDPOINT_BLE: { + max_poll_count = BLE_POLL_COUNT; + polling_interval = BLE_POLL_INTERVAL; + return 0; + } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ + default: + LOG_ERR("Unsupported endpoint"); + return -ENOTSUP; + } +} + +SYS_INIT(trackball_init, APPLICATION, CONFIG_SENSOR_INIT_PRIORITY); + +////////////// +int trackball_endpoint_listener(const zmk_event_t *eh) { + LOG_INF("endpoint changing..."); + + // update polling parameters + switch (zmk_endpoints_selected()) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ZMK_ENDPOINT_USB: { + max_poll_count = USB_POLL_COUNT; + polling_interval = USB_POLL_INTERVAL; + break; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB) */ + +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ZMK_ENDPOINT_BLE: { + max_poll_count = BLE_POLL_COUNT; + polling_interval = BLE_POLL_INTERVAL; + break; + } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ + default: + LOG_ERR("Unsupported endpoint"); + } + + return ZMK_EV_EVENT_BUBBLE; +} + +ZMK_LISTENER(trackball, trackball_endpoint_listener) +ZMK_SUBSCRIPTION(trackball, zmk_endpoint_selection_changed) diff --git a/app/boards/arm/nice_nano/trackball/trackball_new.c b/app/boards/arm/nice_nano/trackball/trackball_new.c new file mode 100644 index 00000000000..62f93ef2259 --- /dev/null +++ b/app/boards/arm/nice_nano/trackball/trackball_new.c @@ -0,0 +1,271 @@ +#ifdef CONFIG_PMW3360 +#define DT_DRV_COMPAT pixart_pmw3360 +#include +#elif defined(CONFIG_PAW3395) +#define DT_DRV_COMPAT pixart_paw3395 +#include +#elif defined(CONFIG_PMW3610) +#define DT_DRV_COMPAT pixart_pmw3610 +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + + +#define SCROLL_DIV_FACTOR 5 +/* #define SCROLL_LAYER_INDEX 4 */ +#define SCROLL_LAYER_INDEX COND_CODE_0(DT_INST_NODE_HAS_PROP(0, scroll_layer), (255), \ + (DT_INST_PROP(0, scroll_layer))) + + +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ +// in us +static int64_t last_interrupt_time = 0; +static int64_t current_interrupt_time = 0; +static int64_t interrupt_interval = 0; +static int64_t handler_duration = 0; +static int64_t send_report_duration = 0; +static int64_t idle_interval = 0; +static int64_t time_buffer = 0; +/* #endif */ + +static int polling_count = 0; +static int max_poll_count = 0; +static int polling_interval = 0; +#define BLE_POLL_COUNT 20 +#define BLE_POLL_INTERVAL 15 // in ms +#define USB_POLL_COUNT 300 +#define USB_POLL_INTERVAL 1 // in ms + + +LOG_MODULE_REGISTER(trackball, CONFIG_SENSOR_LOG_LEVEL); + +// polling work +static void trackball_poll_handler(struct k_work *work) { +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + current_interrupt_time = k_ticks_to_us_floor64(k_uptime_ticks()); + interrupt_interval = current_interrupt_time - last_interrupt_time; + idle_interval = current_interrupt_time - time_buffer; +/* #endif */ + + // get the device pointer + struct pixart_data *data = CONTAINER_OF(work, struct pixart_data, poll_work); + const struct device *dev = data->dev; + + // fetch dx and dy from sensor and save them into pixart_data structure + int ret = sensor_sample_fetch(dev); + if (ret < 0) { + LOG_ERR("fetch: %d", ret); + return; + } + + /* // get the x, y delta */ + /* ret = sensor_channel_get(trackball, SENSOR_CHAN_POS_DX, &dx); */ + /* if (ret < 0) { */ + /* LOG_ERR("get dx: %d", ret); */ + /* return; */ + /* } */ + /* ret = sensor_channel_get(trackball, SENSOR_CHAN_POS_DY, &dy); */ + /* if (ret < 0) { */ + /* LOG_ERR("get dy: %d", ret); */ + /* return; */ + /* } */ + + // remaining scroll from last update + static int16_t scroll_ver_rem = 0, scroll_hor_rem = 0; + static int64_t start_time = 0; + if(data->x != 0 || data->y != 0) { + // process the updated position and send to host + /* k_work_submit_to_queue(zmk_mouse_work_q(), &trackball_update); */ + /* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + start_time = k_ticks_to_us_floor64(k_uptime_ticks()); + /* #endif */ + + // update report with latest position + zmk_hid_mouse_movement_set(0, 0); + zmk_hid_mouse_scroll_set(0, 0); + + const uint8_t layer = zmk_keymap_highest_layer_active(); + if (layer == SCROLL_LAYER_INDEX) { // lower + const int16_t total_hor = data->x + scroll_hor_rem, total_ver = -(data->y + scroll_ver_rem); + scroll_hor_rem = total_hor % SCROLL_DIV_FACTOR; + scroll_ver_rem = total_ver % SCROLL_DIV_FACTOR; + zmk_hid_mouse_scroll_update(total_hor / SCROLL_DIV_FACTOR, total_ver / SCROLL_DIV_FACTOR); + } else { + zmk_hid_mouse_movement_update(CLAMP(data->x, INT8_MIN, INT8_MAX), CLAMP(data->y, INT8_MIN, INT8_MAX)); + } + + // send the report to host + zmk_endpoints_send_mouse_report(); + + send_report_duration = k_ticks_to_us_floor64(k_uptime_ticks()) - start_time; + LOG_INF("Position updated: poll interval: %lld; send time: %lld ; new pos: %d %d",\ + interrupt_interval, send_report_duration, data->x, data->y); + } + +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + time_buffer = k_ticks_to_us_floor64(k_uptime_ticks()); + handler_duration = time_buffer - current_interrupt_time; + LOG_DBG("idle time: %lld ; handler time cost: %lld", \ + idle_interval, handler_duration); + + last_interrupt_time = current_interrupt_time; +} + +// trigger handler +static void trackball_trigger_handler(const struct device *dev, const struct sensor_trigger *trig) { + LOG_INF("I'm new trackball implementation"); + + struct pixart_data *data = dev->data; + + // do not resume motion interrupt by passing-in null handler + struct sensor_trigger trigger = { + .type = SENSOR_TRIG_DATA_READY, + .chan = SENSOR_CHAN_ALL, + }; + if (sensor_trigger_set(dev, &trigger, NULL) < 0) { + LOG_ERR("can't stop motion interrupt line"); + }; + + // start the polling timer (the real work now is dispatched to a timer-based polling) + k_timer_start(&data->poll_timer, K_NO_WAIT, K_MSEC(polling_interval)); +} + +// timer expiry function +void trackball_timer_expiry(struct k_timer *timer) { + struct pixart_data *data = CONTAINER_OF(timer, struct pixart_data, poll_timer); + + // check whether reaching the polling count limit + if(polling_count < max_poll_count) { + // submit polling work to mouse work queue + k_work_submit_to_queue(zmk_mouse_work_q(), &data->poll_work); + + // update status + polling_count++; + } + else { + // stop timer + k_timer_stop(&data->poll_timer); + } +} + +// timer stop function +void trackball_timer_stop(struct k_timer *timer) { + struct pixart_data *data = CONTAINER_OF(timer, struct pixart_data, poll_timer); + const struct device *dev = data->dev; + + // reset polling count + polling_count = 0; + + // resume motion interrupt line by setting the handler to a real object + struct sensor_trigger trigger = { + .type = SENSOR_TRIG_DATA_READY, + .chan = SENSOR_CHAN_ALL, + }; + if (sensor_trigger_set(dev, &trigger, trackball_trigger_handler) < 0) { + LOG_ERR("can't resume motion interrupt line"); + }; +} + + +/* Setup the trigger handler at system powerup */ +// The device instance should be determined in this step. All other functions should only +// use the device poiter passed as an argument. +// In this applaication, the devcie instance 'trackball' is hard-coded as the first +// pixart_pmw3360 node in dts file and used implicitly here. +static int trackball_init() { + LOG_INF("Init trackball_new"); + + // get the sensor device instance + const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); + struct pixart_data *data = dev->data; + + // setup the timer and handler function of the polling work + k_timer_init(&data->poll_timer, trackball_timer_expiry, trackball_timer_stop); + k_work_init(&data->poll_work, trackball_poll_handler); + + // set up the trigger handler (i.e. the entry point to other code in this file) + struct sensor_trigger trigger = { + .type = SENSOR_TRIG_DATA_READY, + .chan = SENSOR_CHAN_ALL, + }; + + int err; + int count = 0; + do { + err = sensor_trigger_set(dev, &trigger, trackball_trigger_handler); + if (err == -EBUSY) { + count++; + k_sleep(K_MSEC(10)); + } + } while (err == -EBUSY && count < 50); + + if (err) { + LOG_ERR("Cannot enable trigger in nice_nano trackball_new.c %d ", err); + return err; + } + + // init polling parameters based on current endpoint + switch (zmk_endpoints_selected()) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ZMK_ENDPOINT_USB: { + max_poll_count = USB_POLL_COUNT; + polling_interval = USB_POLL_INTERVAL; + return 0; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB) */ + +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ZMK_ENDPOINT_BLE: { + max_poll_count = BLE_POLL_COUNT; + polling_interval = BLE_POLL_INTERVAL; + return 0; + } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ + default: + LOG_ERR("Unsupported endpoint"); + return -ENOTSUP; + } +} + +SYS_INIT(trackball_init, APPLICATION, CONFIG_SENSOR_INIT_PRIORITY); + +/* the following code dynamically changes poll rate based on endpoint changing */ +// The code execution is driven by the zmk event system instead of zephyr interrupt routine +int trackball_endpoint_listener(const zmk_event_t *eh) { + LOG_INF("endpoint changing... in trackball_new.c"); + + // update polling parameters + switch (zmk_endpoints_selected()) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ZMK_ENDPOINT_USB: { + max_poll_count = USB_POLL_COUNT; + polling_interval = USB_POLL_INTERVAL; + break; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB) */ + +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ZMK_ENDPOINT_BLE: { + max_poll_count = BLE_POLL_COUNT; + polling_interval = BLE_POLL_INTERVAL; + break; + } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ + default: + LOG_ERR("Unsupported endpoint"); + } + + return ZMK_EV_EVENT_BUBBLE; +} + +ZMK_LISTENER(trackball, trackball_endpoint_listener) +ZMK_SUBSCRIPTION(trackball, zmk_endpoint_selection_changed) diff --git a/app/boards/arm/nice_nano/trackpad/CMakeLists.txt b/app/boards/arm/nice_nano/trackpad/CMakeLists.txt new file mode 100644 index 00000000000..6148e7d61ee --- /dev/null +++ b/app/boards/arm/nice_nano/trackpad/CMakeLists.txt @@ -0,0 +1,4 @@ +zephyr_library() +zephyr_library_sources(trackpad.c) +zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) diff --git a/app/boards/arm/nice_nano/trackpad/trackpad.c b/app/boards/arm/nice_nano/trackpad/trackpad.c new file mode 100644 index 00000000000..b60280cbc00 --- /dev/null +++ b/app/boards/arm/nice_nano/trackpad/trackpad.c @@ -0,0 +1,130 @@ +#define DT_DRV_COMPAT cirque_pinnacle + +#include +#include + +#include +#include +#include +#include + +#define SCROLL_DIV_FACTOR 5 +#define SCROLL_LAYER_INDEX COND_CODE_0(DT_INST_NODE_HAS_PROP(0, scroll_layer), (255), \ + (DT_INST_PROP(0, scroll_layer))) + + +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ +// in us +static int64_t last_interrupt_time = 0; +static int64_t current_interrupt_time = 0; +static int64_t interrupt_interval = 0; +static int64_t handler_duration = 0; +static int64_t send_report_duration = 0; +static int64_t idle_interval = 0; +static int64_t time_buffer = 0; +/* #endif */ + +static struct sensor_value dx, dy, btn; + +const struct device *trackpad = DEVICE_DT_GET(DT_DRV_INST(0)); + +LOG_MODULE_REGISTER(trackpad, CONFIG_SENSOR_LOG_LEVEL); + +/* update and send report */ +static int64_t trackpad_update_handler(struct k_work *work) { +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + int64_t start_time = k_ticks_to_us_floor64(k_uptime_ticks()); +/* #endif */ + + // remaining scroll from last update + static int8_t scroll_ver_rem = 0, scroll_hor_rem = 0; + uint8_t button; + static uint8_t last_button = 0; + static uint8_t last_pressed = 0; + + // update report with latest position + zmk_hid_mouse_movement_set(0, 0); + zmk_hid_mouse_scroll_set(0, 0); + + const uint8_t layer = zmk_keymap_highest_layer_active(); + if (layer == SCROLL_LAYER_INDEX) { // lower + const int16_t total_hor = dx.val1 + scroll_hor_rem, total_ver = -(dy.val1 + scroll_ver_rem); + scroll_hor_rem = total_hor % SCROLL_DIV_FACTOR; + scroll_ver_rem = total_ver % SCROLL_DIV_FACTOR; + zmk_hid_mouse_scroll_update(total_hor / SCROLL_DIV_FACTOR, total_ver / SCROLL_DIV_FACTOR); + button = RCLK; + } else { + zmk_hid_mouse_movement_update(CLAMP(dx.val1, INT8_MIN, INT8_MAX), CLAMP(dy.val1, INT8_MIN, INT8_MAX)); + button = LCLK; + } + + if (!last_pressed && btn.val1) { + zmk_hid_mouse_buttons_press(button); + last_button = button; + } else if (last_pressed && !btn.val1) { + zmk_hid_mouse_buttons_release(last_button); + } + // send the report to host + zmk_endpoints_send_mouse_report(); + last_pressed = btn.val1; + +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + return start_time = k_ticks_to_us_floor64(k_uptime_ticks()) - start_time; +/* #else */ +/* return 0; */ +/* #endif */ +} + +static void handle_trackpad(const struct device *dev, const struct sensor_trigger *trig) { + current_interrupt_time = k_ticks_to_us_floor64(k_uptime_ticks()); + interrupt_interval = current_interrupt_time - last_interrupt_time; + idle_interval = current_interrupt_time - time_buffer; + + + int ret = sensor_sample_fetch(dev); + if (ret < 0) { + LOG_ERR("fetch: %d", ret); + return; + } + + ret = sensor_channel_get(dev, SENSOR_CHAN_POS_DX, &dx); + if (ret < 0) { + LOG_ERR("get dx: %d", ret); + return; + } + ret = sensor_channel_get(dev, SENSOR_CHAN_POS_DY, &dy); + if (ret < 0) { + LOG_ERR("get dy: %d", ret); + return; + } + ret = sensor_channel_get(dev, SENSOR_CHAN_PRESS, &btn); + if (ret < 0) { + LOG_ERR("get btn: %d", ret); + return; + } + + send_report_duration = trackpad_update_handler(NULL); + + time_buffer = k_ticks_to_us_floor64(k_uptime_ticks()); + handler_duration = time_buffer - current_interrupt_time; + + LOG_INF("interrupt interval (us): %lld ; idle: %lld ; handler time cost: %lld",\ + interrupt_interval, idle_interval, handler_duration); + LOG_INF("Send report time cost: %lld; Position: %d %d", send_report_duration, dx.val1, dy.val1); + last_interrupt_time = current_interrupt_time; +} + +static int trackpad_init() { + struct sensor_trigger trigger = { + .type = SENSOR_TRIG_DATA_READY, + .chan = SENSOR_CHAN_ALL, + }; + printk("trackpad"); + if (sensor_trigger_set(trackpad, &trigger, handle_trackpad) < 0) { + LOG_ERR("can't set trigger"); + return -EIO; + }; + return 0; +} + +SYS_INIT(trackpad_init, APPLICATION, CONFIG_ZMK_KSCAN_INIT_PRIORITY); diff --git a/app/boards/arm/nrfmacro/CMakeLists.txt b/app/boards/arm/nrfmacro/CMakeLists.txt new file mode 100644 index 00000000000..541f6bc5406 --- /dev/null +++ b/app/boards/arm/nrfmacro/CMakeLists.txt @@ -0,0 +1,18 @@ +# +# Copyright (c) 2021 Darryl deHaan +# SPDX-License-Identifier: MIT +# + +if(CONFIG_ZMK_DISPLAY AND CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM) + add_subdirectory_ifdef(CONFIG_NRFMACRO_EPD_DISPLAY epd_screen) + # add_subdirectory_ifdef(CONFIG_NRFMACRO_LCD_DISPLAY lcd_screen) + # add_subdirectory_ifdef(CONFIG_NRFMACRO_OLED_DISPLAY oled_screen) +endif() + +if (CONFIG_NRFMACRO_POINTDEVICE) + add_subdirectory_ifdef(CONFIG_PINNACLE trackpad) + add_subdirectory_ifdef(CONFIG_PMW33XX trackball) + add_subdirectory_ifdef(CONFIG_PMW3360 trackball) + add_subdirectory_ifdef(CONFIG_PAW3395 trackball) + add_subdirectory_ifdef(CONFIG_PMW3610 trackball) +endif() diff --git a/app/boards/arm/nrfmacro/Kconfig b/app/boards/arm/nrfmacro/Kconfig new file mode 100644 index 00000000000..7ad73654457 --- /dev/null +++ b/app/boards/arm/nrfmacro/Kconfig @@ -0,0 +1,5 @@ +config BOARD_ENABLE_DCDC + bool "Enable DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on (BOARD_NRFMACRO) \ No newline at end of file diff --git a/app/boards/arm/nrfmacro/Kconfig.board b/app/boards/arm/nrfmacro/Kconfig.board new file mode 100644 index 00000000000..234af2c76f4 --- /dev/null +++ b/app/boards/arm/nrfmacro/Kconfig.board @@ -0,0 +1,8 @@ +# nrfmacro board configuration + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_NRFMACRO + bool "nrfmacro" + depends on SOC_NRF52840_QIAA diff --git a/app/boards/arm/nrfmacro/Kconfig.defconfig b/app/boards/arm/nrfmacro/Kconfig.defconfig new file mode 100644 index 00000000000..cb691032f2c --- /dev/null +++ b/app/boards/arm/nrfmacro/Kconfig.defconfig @@ -0,0 +1,242 @@ +# Electronut Labs Papyr board configuration + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_NRFMACRO + +config BOARD + default "nrfmacro" + +# DISPLAY options: oled, epd, lcd, default: no display +choice + prompt "nrfmacro Display option" + depends on ZMK_DISPLAY + help + Specify the type of the display peripheral. + +# config NRFMACRO_NO_DISPLAY +# bool "No display screen" + +config NRFMACRO_EPD_DISPLAY + bool "Use epaper display" + select SPI + select IL0323 + select LVGL_USE_CONT + select LVGL_FONT_MONTSERRAT_26 + select LVGL_FONT_MONTSERRAT_20 + select LVGL_FONT_MONTSERRAT_16 + select LVGL_USE_LABEL + select LVGL_USE_IMG + +config NRFMACRO_OLED_DISPLAY + bool "Ues OLED display" + select I2C + select SSD1306 + select SSD1306_REVERSE_MODE + +config NRFMACRO_LCD_DISPLAY + bool "Use SHARP memory LCD" + select SPI + select LS0XX + select LVGL_USE_CONT + select LVGL_FONT_MONTSERRAT_26 + # select LVGL_FONT_MONTSERRAT_20 + # select LVGL_FONT_MONTSERRAT_16 + # select LVGL_USE_LABEL + # select LVGL_USE_IMG + +endchoice + +# Role of the keyboard in split setup, default is master (i.e., central) +## NOTE: this is a dedicated config option for nrfmacro board, so that all shields +## using this board can share the some configuration. It's mainly used for controlling +## which widget to show on different side of the keyboard +choice + prompt "Role of the keyboard" + help + Specify the role of the keyboard + +config NRFMACRO_SHIELD_MASTER + bool "master side, in charge of communication with host" + +config NRFMACRO_SHIELD_SLAVE + bool "slave side, acting as a peripheral to master side" + +endchoice + +# Rotate the display screen 180 degree (upside down) +config NRFMACRO_ROTATE_SCREEN + bool "rotate the display screen upside down" + +# Show product mark on the screen +config NRFMACRO_SCREEN_MARK_LOGO + bool "show the mark logo on the screen" + +choice + prompt "Keyboard logo on the display screen" + help + Specify which logo to show on the centre of screen + +config NRFMACRO_SCREEN_STANDARD_LOGO + bool "Use the standard logo distributed with the firmware source" + +config NRFMACRO_SCREEN_CUSTOM_LOGO + bool "Use the customized logo designed by yourself" + +endchoice + +# Customizing margin of the display screen +config NRFMACRO_SCREEN_TOP_MARGIN + int "top margin of display screen in pixel" + depends on ZMK_DISPLAY + default 2 + +config NRFMACRO_SCREEN_BOTTOM_MARGIN + int "bottom margin of display screen in pixel" + depends on ZMK_DISPLAY + default 2 + +config NRFMACRO_SCREEN_LEFT_MARGIN + int "left margin of display screen in pixel" + depends on ZMK_DISPLAY + default 2 + +config NRFMACRO_SCREEN_RIGHT_MARGIN + int "right margin of display screen in pixel" + depends on ZMK_DISPLAY + default 2 + +# USB STACK setup +if USB_DEVICE_STACK + +config USB_NRFX + default y + +endif # USB_DEVICE_STACK + +config BT_CTLR + default BT + +config ZMK_BLE + default y + +config ZMK_USB + default y + +# DISPLAY setup +## common configuration +if ZMK_DISPLAY +config ZMK_DISPLAY_DEDICATED_THREAD_STACK_SIZE + default 2048 + +endif # ZMK_DISPLAY + +if ZMK_DISPLAY_STATUS_SCREEN_CUSTOM + +if NRFMACRO_SHIELD_SLAVE +config LVGL_FONT_MONTSERRAT_16 + default y + +choice LVGL_THEME_DEFAULT_FONT_NORMAL + default LVGL_THEME_DEFAULT_FONT_NORMAL_MONTSERRAT_16 + +endchoice + +config LVGL_FONT_MONTSERRAT_12 + default y + +choice LVGL_THEME_DEFAULT_FONT_SMALL + default LVGL_THEME_DEFAULT_FONT_SMALL_MONTSERRAT_12 + +endchoice +endif + +endif # ZMK_DISPLAY_STATUS_SCREEN_CUSTOM + +## dedicated configuration +if LVGL + +config LVGL_BITS_PER_PIXEL + default 1 + +choice LVGL_COLOR_DEPTH + default LVGL_COLOR_DEPTH_1 +endchoice + +config LVGL_USE_CONT + default y + +## oled display configuration +if NRFMACRO_OLED_DISPLAY +config LVGL_HOR_RES_MAX + default 128 + +config LVGL_VER_RES_MAX + default 32 + +config LVGL_VDB_SIZE + default 64 + +config LVGL_DPI + default 148 +endif # NRFMACRO_OLED_DISPLAY + +## epd display configuration +if NRFMACRO_EPD_DISPLAY +config NRFMACRO_EPD_ROTATE_180 + bool "rotate the epd upside-down" + +config LVGL_HOR_RES_MAX + default 80 + +config LVGL_VER_RES_MAX + default 128 + +config LVGL_VDB_SIZE + default 100 + +config LVGL_DPI + default 145 +endif # NRFMACRO_EPD_DISPLAY + +## memory lcd display configuration +if NRFMACRO_LCD_DISPLAY +choice LVGL_THEME_DEFAULT_FONT_SMALL + default LVGL_THEME_DEFAULT_FONT_SMALL_MONTSERRAT_36 +endchoice + +config LVGL_HOR_RES_MAX + default 160 + +config LVGL_VER_RES_MAX + default 68 + +config LVGL_VDB_SIZE + default 16 + +config LVGL_DPI + default 30 +endif # NRFMACRO_LCD_DISPLAY + +endif # LVGL + +# custom widgets configuration +menuconfig CUSTOM_WIDGET_BATTERY_STATUS + bool "custom battery status widget" + +menuconfig CUSTOM_WIDGET_OUTPUT_STATUS + bool "custom output status widget" + +menuconfig CUSTOM_WIDGET_LAYER_STATUS + bool "custom layer status widget" + +menuconfig CUSTOM_WIDGET_PERIPHERAL_STATUS + bool "custom layer status widget" + +# add point device +config NRFMACRO_POINTDEVICE + bool "add support for point device" + select SPI + +endif # BOARD_NRFMACRO diff --git a/app/boards/arm/nrfmacro/arduino_pro_micro_pins.dtsi b/app/boards/arm/nrfmacro/arduino_pro_micro_pins.dtsi new file mode 100644 index 00000000000..537aaed35b0 --- /dev/null +++ b/app/boards/arm/nrfmacro/arduino_pro_micro_pins.dtsi @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + +/ { + pro_micro: connector { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 8 0> /* D0 */ + , <1 0 &gpio0 6 0> /* D1 */ + , <2 0 &gpio0 15 0> /* D2 */ + , <3 0 &gpio0 17 0> /* D3 */ + , <4 0 &gpio0 20 0> /* D4/A6 */ + , <5 0 &gpio0 13 0> /* D5 */ + , <6 0 &gpio0 24 0> /* D6/A7 */ + , <7 0 &gpio0 9 0> /* D7 */ + , <8 0 &gpio0 10 0> /* D8/A8 */ + , <9 0 &gpio1 6 0> /* D9/A9 */ + , <10 0 &gpio1 11 0> /* D10/A10 */ + , <16 0 &gpio0 28 0> /* D16 */ + , <14 0 &gpio0 3 0> /* D14 */ + , <15 0 &gpio1 13 0> /* D15 */ + , <18 0 &gpio0 2 0> /* D18/A0 */ + , <19 0 &gpio0 29 0> /* D19/A1 */ + , <20 0 &gpio0 31 0> /* D20/A2 */ + , <21 0 &gpio0 30 0> /* D21/A3 */ + ; + }; + + pro_micro_a: connector_a { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 2 0> /* D18/A0 */ + , <1 0 &gpio0 29 0> /* D19/A1 */ + , <2 0 &gpio0 31 0> /* D20/A2 */ + , <3 0 &gpio0 30 0> /* D21/A3 */ + , <6 0 &gpio0 20 0> /* D4/A6 */ + , <7 0 &gpio0 24 0> /* D6/A7 */ + , <8 0 &gpio0 10 0> /* D8/A8 */ + , <9 0 &gpio1 6 0> /* D9/A9 */ + , <10 0 &gpio1 11 0> /* D10/A10 */ + ; + }; +}; + + +pro_micro_d: &pro_micro {}; +pro_micro_i2c: &i2c0 {}; +pro_micro_spi: &spi0 {}; +pro_micro_serial: &uart0 {}; diff --git a/app/boards/arm/nrfmacro/board.cmake b/app/boards/arm/nrfmacro/board.cmake new file mode 100644 index 00000000000..b7feee2ee9e --- /dev/null +++ b/app/boards/arm/nrfmacro/board.cmake @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: MIT + +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/app/boards/arm/nrfmacro/custom_status_screen.c b/app/boards/arm/nrfmacro/custom_status_screen.c new file mode 100644 index 00000000000..7347691d414 --- /dev/null +++ b/app/boards/arm/nrfmacro/custom_status_screen.c @@ -0,0 +1,72 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include "widgets/battery_status.h" +#include "widgets/output_status.h" +#include "widgets/layer_status.h" +#include "custom_status_screen.h" + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +LV_IMG_DECLARE(zenlogo); +LV_IMG_DECLARE(layers2); + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_BATTERY_STATUS) +static struct zmk_widget_battery_status battery_status_widget; +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS) +static struct zmk_widget_output_status output_status_widget; +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_LAYER_STATUS) +static struct zmk_widget_layer_status layer_status_widget; +#endif + +lv_obj_t *zmk_display_status_screen() { + + lv_obj_t *screen; + screen = lv_obj_create(NULL, NULL); + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_BATTERY_STATUS) + zmk_widget_battery_status_init(&battery_status_widget, screen); + lv_obj_align(zmk_widget_battery_status_obj(&battery_status_widget), NULL, LV_ALIGN_IN_TOP_MID, 0, 2); +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS) + zmk_widget_output_status_init(&output_status_widget, screen); + lv_obj_align(zmk_widget_output_status_obj(&output_status_widget), NULL, LV_ALIGN_IN_TOP_MID, 0, 41); +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_LAYER_STATUS) + //lv_style_set_pad_inner(&layerstyle, LV_STATE_DEFAULT, 12); + //lv_obj_add_style(&layer_status_widget, LV_WIDGET_PART_MAIN, &layerstyle); + zmk_widget_layer_status_init(&layer_status_widget, screen); + lv_obj_align(zmk_widget_layer_status_obj(&layer_status_widget), NULL, LV_ALIGN_IN_BOTTOM_MID, 0, -5); +#endif + +#if IS_ENABLED(CONFIG_NRFMACRO_SHIELD_SLAVE) + lv_obj_t * zenlogo_icon; + zenlogo_icon = lv_img_create(screen, NULL); + lv_img_set_src(zenlogo_icon, &zenlogo); + lv_obj_align(zenlogo_icon, NULL, LV_ALIGN_IN_BOTTOM_MID, 2, -5); +#endif + +#if IS_ENABLED(CONFIG_NRFMACRO_SHIELD_MASTER) + lv_obj_t * LayersHeading; + LayersHeading = lv_img_create(screen, NULL); + lv_obj_align(LayersHeading, NULL, LV_ALIGN_IN_BOTTOM_MID, 8, 5); + lv_img_set_src(LayersHeading, &layers2); +#endif + + //lv_task_handler(); + lv_refr_now(NULL); + //display_blanking_off(display_dev); + + return screen; +} diff --git a/app/boards/arm/nrfmacro/custom_status_screen.h b/app/boards/arm/nrfmacro/custom_status_screen.h new file mode 100644 index 00000000000..dc203fd1b49 --- /dev/null +++ b/app/boards/arm/nrfmacro/custom_status_screen.h @@ -0,0 +1,10 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#pragma once + +#include \ No newline at end of file diff --git a/app/boards/arm/nrfmacro/epd_screen/CMakeLists.txt b/app/boards/arm/nrfmacro/epd_screen/CMakeLists.txt new file mode 100644 index 00000000000..d5ca27e6b5a --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/CMakeLists.txt @@ -0,0 +1,7 @@ +# +# Copyright (c) 2021 Darryl deHaan +# SPDX-License-Identifier: MIT +# + +add_subdirectory_ifdef(CONFIG_NRFMACRO_SHIELD_MASTER master) +add_subdirectory_ifdef(CONFIG_NRFMACRO_SHIELD_SLAVE slave) diff --git a/app/boards/arm/nrfmacro/epd_screen/master/CMakeLists.txt b/app/boards/arm/nrfmacro/epd_screen/master/CMakeLists.txt new file mode 100644 index 00000000000..0d9748f1f3c --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/CMakeLists.txt @@ -0,0 +1,55 @@ +# +# Copyright (c) 2021 Darryl deHaan +# SPDX-License-Identifier: MIT +# + +# target_sources(app PRIVATE status_screen.c) +# target_sources_ifdef(CONFIG_CUSTOM_WIDGET_BATTERY_STATUS app PRIVATE battery_status.c) +# target_sources_ifdef(CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS app PRIVATE output_status.c) +# target_sources_ifdef(CONFIG_CUSTOM_WIDGET_LAYER_STATUS app PRIVATE layer_status.c) + +zephyr_library() + +zephyr_library_include_directories(${ZEPHYR_LVGL_MODULE_DIR}) +zephyr_library_include_directories(${ZEPHYR_BASE}/lib/gui/lvgl/) +zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) + +zephyr_library_sources(status_screen.c) +zephyr_library_sources_ifdef(CONFIG_CUSTOM_WIDGET_BATTERY_STATUS battery_status.c) +zephyr_library_sources_ifdef(CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS output_status.c) +zephyr_library_sources_ifdef(CONFIG_CUSTOM_WIDGET_LAYER_STATUS layer_status.c) + +if (CONFIG_CUSTOM_WIDGET_BATTERY_STATUS) + zephyr_library_sources(icons/batt_100.c) + zephyr_library_sources(icons/batt_100_chg.c) + zephyr_library_sources(icons/batt_75.c) + zephyr_library_sources(icons/batt_75_chg.c) + zephyr_library_sources(icons/batt_50.c) + zephyr_library_sources(icons/batt_50_chg.c) + zephyr_library_sources(icons/batt_25.c) + zephyr_library_sources(icons/batt_25_chg.c) + zephyr_library_sources(icons/batt_5.c) + zephyr_library_sources(icons/batt_5_chg.c) + zephyr_library_sources(icons/batt_0.c) + zephyr_library_sources(icons/batt_0_chg.c) +endif() + +if (CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS) + zephyr_library_sources(icons/bluetooth_disconnected.c) + zephyr_library_sources(icons/USB_connected.c) + zephyr_library_sources(icons/bluetooth_connected_1.c) + zephyr_library_sources(icons/bluetooth_connected_2.c) + zephyr_library_sources(icons/bluetooth_connected_3.c) + zephyr_library_sources(icons/bluetooth_connected_4.c) + zephyr_library_sources(icons/bluetooth_connected_5.c) + zephyr_library_sources(icons/bluetooth_advertising_1.c) + zephyr_library_sources(icons/bluetooth_advertising_2.c) + zephyr_library_sources(icons/bluetooth_advertising_3.c) + zephyr_library_sources(icons/bluetooth_advertising_4.c) + zephyr_library_sources(icons/bluetooth_advertising_5.c) +endif() + +if (CONFIG_CUSTOM_WIDGET_LAYER_STATUS) + zephyr_library_sources(icons/layers.c) +endif() diff --git a/app/boards/arm/nrfmacro/epd_screen/master/battery_status.c b/app/boards/arm/nrfmacro/epd_screen/master/battery_status.c new file mode 100644 index 00000000000..6e8a5282f07 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/battery_status.c @@ -0,0 +1,165 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include "battery_status.h" +#include +#include +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); +static lv_style_t label_style; + +LV_IMG_DECLARE(batt_100); +LV_IMG_DECLARE(batt_100_chg); +LV_IMG_DECLARE(batt_75); +LV_IMG_DECLARE(batt_75_chg); +LV_IMG_DECLARE(batt_50); +LV_IMG_DECLARE(batt_50_chg); +LV_IMG_DECLARE(batt_25); +LV_IMG_DECLARE(batt_25_chg); +LV_IMG_DECLARE(batt_5); +LV_IMG_DECLARE(batt_5_chg); +LV_IMG_DECLARE(batt_0); +LV_IMG_DECLARE(batt_0_chg); + +static bool style_initialized = false; + +void battery_status_init() { + + if (style_initialized) { + return; + } + + style_initialized = true; + lv_style_init(&label_style); + lv_style_set_text_font(&label_style, LV_STATE_DEFAULT, &lv_font_montserrat_26); + lv_style_set_text_letter_space(&label_style, LV_STATE_DEFAULT, 1); + lv_style_set_text_line_space(&label_style, LV_STATE_DEFAULT, 1); + lv_style_set_text_color(&label_style, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_style_set_bg_color(&label_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); + + //lv_obj_t * batt_full_chg_icon = lv_img_create(lv_scr_act(), NULL); + //lv_img_set_src(batt_full_chg_icon, &batt_full_chg); +} + +K_MUTEX_DEFINE(battery_status_mutex); + +struct { + uint8_t level; +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + bool usb_present; +#endif +} battery_status_state; + +void set_battery_symbol(lv_obj_t *icon) { + + k_mutex_lock(&battery_status_mutex, K_FOREVER); + + uint8_t level = battery_status_state.level; + +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + if (level > 95) { + if (battery_status_state.usb_present) { + lv_img_set_src(icon, &batt_100_chg); + }else{ + lv_img_set_src(icon, &batt_100); + } + } else if (level > 74) { + if (battery_status_state.usb_present) { + lv_img_set_src(icon, &batt_75_chg); + }else{ + lv_img_set_src(icon, &batt_75); + } + } else if (level > 49) { + if (battery_status_state.usb_present) { + lv_img_set_src(icon, &batt_50_chg); + }else{ + lv_img_set_src(icon, &batt_50); + } + } else if (level > 24) { + if (battery_status_state.usb_present) { + lv_img_set_src(icon, &batt_25_chg); + }else{ + lv_img_set_src(icon, &batt_25); + } + } else if (level > 5) { + if (battery_status_state.usb_present) { + lv_img_set_src(icon, &batt_5_chg); + }else{ + lv_img_set_src(icon, &batt_5); + } + } else { + if (battery_status_state.usb_present) { + lv_img_set_src(icon, &batt_0_chg); + }else{ + lv_img_set_src(icon, &batt_0); + } + } + //lv_label_set_text(label, text); + //lv_img_set_src(icon, ); + +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + + k_mutex_unlock(&battery_status_mutex); + +} + +int zmk_widget_battery_status_init(struct zmk_widget_battery_status *widget, lv_obj_t *parent) { + battery_status_init(); + //widget->obj = lv_label_create(parent, NULL); + widget->obj = lv_img_create(parent, NULL); + //widget->obj2 = lv_label_create(parent, NULL); + lv_obj_add_style(widget->obj, LV_LABEL_PART_MAIN, &label_style); + + //lv_obj_set_size(widget->obj, 40, 15); + set_battery_symbol(widget->obj); + + sys_slist_append(&widgets, &widget->node); + + return 0; +} + +lv_obj_t *zmk_widget_battery_status_obj(struct zmk_widget_battery_status *widget) { + return widget->obj; +} + +void battery_status_update_cb(struct k_work *work) { + struct zmk_widget_battery_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_battery_symbol(widget->obj); } +} + +K_WORK_DEFINE(battery_status_update_work, battery_status_update_cb); + +int battery_status_listener(const zmk_event_t *eh) { + k_mutex_lock(&battery_status_mutex, K_FOREVER); + + battery_status_state.level = bt_bas_get_battery_level(); + +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + battery_status_state.usb_present = zmk_usb_is_powered(); +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + + k_mutex_unlock(&battery_status_mutex); + + k_work_submit_to_queue(zmk_display_work_q(), &battery_status_update_work); + return ZMK_EV_EVENT_BUBBLE; +} + +ZMK_LISTENER(widget_battery_status, battery_status_listener) +ZMK_SUBSCRIPTION(widget_battery_status, zmk_battery_state_changed); +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) +ZMK_SUBSCRIPTION(widget_battery_status, zmk_usb_conn_state_changed); +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ diff --git a/app/boards/arm/nrfmacro/epd_screen/master/battery_status.h b/app/boards/arm/nrfmacro/epd_screen/master/battery_status.h new file mode 100644 index 00000000000..c2ad4bf4094 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/battery_status.h @@ -0,0 +1,20 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#pragma once + +#include + +#include + +struct zmk_widget_battery_status { + sys_snode_t node; + lv_obj_t *obj; +}; + +int zmk_widget_battery_status_init(struct zmk_widget_battery_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_battery_status_obj(struct zmk_widget_battery_status *widget); \ No newline at end of file diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/CMakeLists.txt b/app/boards/arm/nrfmacro/epd_screen/master/icons/CMakeLists.txt new file mode 100644 index 00000000000..19af8ead415 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/CMakeLists.txt @@ -0,0 +1,4 @@ +# +# Copyright (c) 2021 Darryl deHaan +# SPDX-License-Identifier: MIT +# \ No newline at end of file diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/USB_connected.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/USB_connected.c new file mode 100644 index 00000000000..8cf0badc38a --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/USB_connected.c @@ -0,0 +1,63 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_USB_CONNECTED +#define LV_ATTRIBUTE_IMG_USB_CONNECTED +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_USB_CONNECTED uint8_t USB_connected_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0xff, 0xff, 0xc0, + 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0x00, 0xff, 0xff, 0xff, 0xc0, + 0x01, 0xff, 0xff, 0xff, 0x80, + 0x03, 0xff, 0xff, 0xff, 0xfe, + 0x07, 0xff, 0xff, 0xff, 0xff, + 0x07, 0x1e, 0x30, 0x38, 0x07, + 0x0f, 0x1c, 0x20, 0x38, 0x07, + 0x0f, 0x1c, 0x47, 0x10, 0xc3, + 0x3e, 0x1c, 0x43, 0xf1, 0xc7, + 0x7e, 0x3c, 0x60, 0x70, 0x0e, + 0x7e, 0x3c, 0x70, 0x30, 0x0e, + 0x7e, 0x38, 0xfc, 0x33, 0xc7, + 0xfe, 0x18, 0x8f, 0x23, 0x87, + 0x0e, 0x00, 0xc6, 0x20, 0x07, + 0x0f, 0x01, 0xe0, 0x60, 0x0e, + 0x0f, 0x87, 0xf0, 0xe0, 0x3e, + 0x07, 0xff, 0xff, 0xff, 0xfc, + 0x07, 0xff, 0xff, 0xff, 0xf0, + 0x03, 0xff, 0xff, 0xfe, 0x00, + 0x01, 0xff, 0xff, 0xfc, 0x00, + 0x00, 0x7f, 0xff, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t USB_connected = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 164, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = USB_connected_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_0.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_0.c new file mode 100644 index 00000000000..d061f1d87bf --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_0.c @@ -0,0 +1,65 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_0 +#define LV_ATTRIBUTE_IMG_BATT_0 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_0 uint8_t batt_0_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x00, 0x00, + 0x7f, 0xfd, 0xff, 0x7f, 0xf8, + 0xff, 0xfd, 0xff, 0x7f, 0xfc, + 0xff, 0xfd, 0xff, 0x7f, 0xfc, + 0xff, 0xfc, 0xfe, 0x7f, 0xfc, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x0f, + 0xf0, 0x00, 0x7c, 0x00, 0x0f, + 0xf0, 0x00, 0x7c, 0x00, 0x0f, + 0xf0, 0x00, 0x7c, 0x00, 0x0f, + 0xf0, 0x00, 0x7c, 0x00, 0x3f, + 0xf0, 0x00, 0x7c, 0x00, 0x3f, + 0xf0, 0x00, 0x7c, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0x01, 0xff, 0xfc, + 0xff, 0xff, 0x01, 0xff, 0xfc, + 0xff, 0xfe, 0x7c, 0xff, 0xfc, + 0x7f, 0xfc, 0xfe, 0x7f, 0xf8, + 0x00, 0x01, 0xff, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_0 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_0_map, +}; + diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_0_chg.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_0_chg.c new file mode 100644 index 00000000000..e05e1524f09 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_0_chg.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_0_CHG +#define LV_ATTRIBUTE_IMG_BATT_0_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_0_CHG uint8_t batt_0_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, + 0x00, 0x00, 0x03, 0x80, 0x00, + 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, + 0xff, 0xff, 0xdf, 0x7f, 0xfc, + 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf0, 0x01, 0xfe, 0x00, 0x3f, + 0xf0, 0x03, 0xfc, 0x00, 0x3f, + 0xf0, 0x07, 0xfc, 0x00, 0x0f, + 0xf0, 0x0f, 0xff, 0xe0, 0x0f, + 0xf0, 0x1f, 0xff, 0xc0, 0x0f, + 0xf0, 0x00, 0x7f, 0x80, 0x0f, + 0xf0, 0x00, 0x7f, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfc, 0x00, 0x3f, + 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, + 0xff, 0xfb, 0xef, 0xff, 0xfc, + 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_0_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_0_chg_map, +}; + diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_100.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_100.c new file mode 100644 index 00000000000..915472c3e2b --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_100.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_100 +#define LV_ATTRIBUTE_IMG_BATT_100 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_100 uint8_t batt_100_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0xff, 0xff, 0xff, 0x3f, + 0xf3, 0xff, 0xff, 0xff, 0x3f, + 0xf3, 0xff, 0xff, 0xff, 0x0f, + 0xf3, 0xff, 0xff, 0xff, 0x0f, + 0xf3, 0xff, 0xff, 0xff, 0x0f, + 0xf3, 0xff, 0xff, 0xff, 0x0f, + 0xf3, 0xff, 0xff, 0xff, 0x3f, + 0xf3, 0xff, 0xff, 0xff, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_100 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_100_map, +}; + diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_100_chg.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_100_chg.c new file mode 100644 index 00000000000..9ad05d61c76 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_100_chg.c @@ -0,0 +1,65 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_100_CHG +#define LV_ATTRIBUTE_IMG_BATT_100_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_100_CHG uint8_t batt_100_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, + 0x00, 0x00, 0x03, 0x80, 0x00, + 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, + 0xff, 0xff, 0xdf, 0x7f, 0xfc, + 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf3, 0xfd, 0xfe, 0xff, 0x3f, + 0xf3, 0xfb, 0xfd, 0xff, 0x3f, + 0xf3, 0xf7, 0xfc, 0x07, 0x0f, + 0xf3, 0xef, 0xff, 0xef, 0x0f, + 0xf3, 0xdf, 0xff, 0xdf, 0x0f, + 0xf3, 0x80, 0x7f, 0xbf, 0x0f, + 0xf3, 0xff, 0x7f, 0x7f, 0x3f, + 0xf3, 0xfe, 0xfe, 0xff, 0x3f, + 0xf0, 0x00, 0xfc, 0x00, 0x3f, + 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, + 0xff, 0xfb, 0xef, 0xff, 0xfc, + 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_100_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_100_chg_map, +}; + diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_25.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_25.c new file mode 100644 index 00000000000..1dba62c2f6c --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_25.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_25 +#define LV_ATTRIBUTE_IMG_BATT_25 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_25 uint8_t batt_25_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0xfc, 0x00, 0x00, 0x3f, + 0xf3, 0xfc, 0x00, 0x00, 0x3f, + 0xf3, 0xfc, 0x00, 0x00, 0x0f, + 0xf3, 0xfc, 0x00, 0x00, 0x0f, + 0xf3, 0xfc, 0x00, 0x00, 0x0f, + 0xf3, 0xfc, 0x00, 0x00, 0x0f, + 0xf3, 0xfc, 0x00, 0x00, 0x3f, + 0xf3, 0xfc, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_25 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_25_map, +}; + diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_25_chg.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_25_chg.c new file mode 100644 index 00000000000..544e71db7c5 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_25_chg.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_25_CHG +#define LV_ATTRIBUTE_IMG_BATT_25_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_25_CHG uint8_t batt_25_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, + 0x00, 0x00, 0x03, 0x80, 0x00, + 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, + 0xff, 0xff, 0xdf, 0x7f, 0xfc, + 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf3, 0xf9, 0xfe, 0x00, 0x3f, + 0xf3, 0xfb, 0xfc, 0x00, 0x3f, + 0xf3, 0xf7, 0xfc, 0x00, 0x0f, + 0xf3, 0xef, 0xff, 0xe0, 0x0f, + 0xf3, 0xdf, 0xff, 0xc0, 0x0f, + 0xf3, 0x80, 0x7f, 0x80, 0x0f, + 0xf3, 0xf8, 0x7f, 0x00, 0x3f, + 0xf3, 0xf8, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfc, 0x00, 0x3f, + 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, + 0xff, 0xfb, 0xef, 0xff, 0xfc, + 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_25_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_25_chg_map, +}; + diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_5.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_5.c new file mode 100644 index 00000000000..a8c5ded9289 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_5.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_5 +#define LV_ATTRIBUTE_IMG_BATT_5 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_5 uint8_t batt_5_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0x00, 0x00, 0x00, 0x0f, + 0xf3, 0x00, 0x00, 0x00, 0x0f, + 0xf3, 0x00, 0x00, 0x00, 0x0f, + 0xf3, 0x00, 0x00, 0x00, 0x0f, + 0xf3, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_5 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_5_map, +}; + diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_50.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_50.c new file mode 100644 index 00000000000..3c93ae5bc71 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_50.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_50 +#define LV_ATTRIBUTE_IMG_BATT_50 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_50 uint8_t batt_50_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0xff, 0xf0, 0x00, 0x3f, + 0xf3, 0xff, 0xf0, 0x00, 0x3f, + 0xf3, 0xff, 0xf0, 0x00, 0x0f, + 0xf3, 0xff, 0xf0, 0x00, 0x0f, + 0xf3, 0xff, 0xf0, 0x00, 0x0f, + 0xf3, 0xff, 0xf0, 0x00, 0x0f, + 0xf3, 0xff, 0xf0, 0x00, 0x3f, + 0xf3, 0xff, 0xf0, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_50 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_50_map, +}; + diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_50_chg.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_50_chg.c new file mode 100644 index 00000000000..b21b4e25df3 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_50_chg.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_50_CHG +#define LV_ATTRIBUTE_IMG_BATT_50_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_50_CHG uint8_t batt_50_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, + 0x00, 0x00, 0x03, 0x80, 0x00, + 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, + 0xff, 0xff, 0xdf, 0x7f, 0xfc, + 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf3, 0xfd, 0xfe, 0x00, 0x3f, + 0xf3, 0xfb, 0xfc, 0x00, 0x3f, + 0xf3, 0xf7, 0xfc, 0x00, 0x0f, + 0xf3, 0xef, 0xff, 0xe0, 0x0f, + 0xf3, 0xdf, 0xff, 0xc0, 0x0f, + 0xf3, 0x80, 0x7f, 0x80, 0x0f, + 0xf3, 0xff, 0x7f, 0x00, 0x3f, + 0xf3, 0xfe, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfc, 0x00, 0x3f, + 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, + 0xff, 0xfb, 0xef, 0xff, 0xfc, + 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_50_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_50_chg_map, +}; + diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_5_chg.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_5_chg.c new file mode 100644 index 00000000000..da96fc4da1b --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_5_chg.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_5_CHG +#define LV_ATTRIBUTE_IMG_BATT_5_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_5_CHG uint8_t batt_5_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, + 0x00, 0x00, 0x03, 0x80, 0x00, + 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, + 0xff, 0xff, 0xdf, 0x7f, 0xfc, + 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf3, 0x01, 0xfe, 0x00, 0x3f, + 0xf3, 0x03, 0xfc, 0x00, 0x3f, + 0xf3, 0x07, 0xfc, 0x00, 0x0f, + 0xf3, 0x0f, 0xff, 0xe0, 0x0f, + 0xf3, 0x1f, 0xff, 0xc0, 0x0f, + 0xf3, 0x00, 0x7f, 0x80, 0x0f, + 0xf3, 0x00, 0x7f, 0x00, 0x3f, + 0xf3, 0x00, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfc, 0x00, 0x3f, + 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, + 0xff, 0xfb, 0xef, 0xff, 0xfc, + 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_5_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_5_chg_map, +}; + diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_75.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_75.c new file mode 100644 index 00000000000..cbba208ef88 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_75.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_75 +#define LV_ATTRIBUTE_IMG_BATT_75 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_75 uint8_t batt_75_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0xff, 0xff, 0xe0, 0x3f, + 0xf3, 0xff, 0xff, 0xe0, 0x3f, + 0xf3, 0xff, 0xff, 0xe0, 0x0f, + 0xf3, 0xff, 0xff, 0xe0, 0x0f, + 0xf3, 0xff, 0xff, 0xe0, 0x0f, + 0xf3, 0xff, 0xff, 0xe0, 0x0f, + 0xf3, 0xff, 0xff, 0xe0, 0x3f, + 0xf3, 0xff, 0xff, 0xe0, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_75 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_75_map, +}; + diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_75_chg.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_75_chg.c new file mode 100644 index 00000000000..b2c2298d3b2 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/batt_75_chg.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_75_CHG +#define LV_ATTRIBUTE_IMG_BATT_75_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_75_CHG uint8_t batt_75_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, + 0x00, 0x00, 0x03, 0x80, 0x00, + 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, + 0xff, 0xff, 0xdf, 0x7f, 0xfc, + 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf3, 0xfd, 0xfe, 0xe0, 0x3f, + 0xf3, 0xfb, 0xfd, 0xe0, 0x3f, + 0xf3, 0xf7, 0xfc, 0x00, 0x0f, + 0xf3, 0xef, 0xff, 0xe0, 0x0f, + 0xf3, 0xdf, 0xff, 0xc0, 0x0f, + 0xf3, 0x80, 0x7f, 0xa0, 0x0f, + 0xf3, 0xff, 0x7f, 0x60, 0x3f, + 0xf3, 0xfe, 0xfe, 0xe0, 0x3f, + 0xf0, 0x00, 0xfc, 0x00, 0x3f, + 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, + 0xff, 0xfb, 0xef, 0xff, 0xfc, + 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_75_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_75_chg_map, +}; + diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising.c new file mode 100644 index 00000000000..89809d1ffbf --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising.c @@ -0,0 +1,66 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING uint8_t bluetooth_advertising_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, + 0x00, 0x7f, 0x00, 0x00, + 0x20, 0x7f, 0x80, 0x00, + 0x70, 0x77, 0xc0, 0x00, + 0xf8, 0x73, 0xe0, 0xc0, + 0x7c, 0x71, 0xe0, 0xe0, + 0x3e, 0x73, 0xc0, 0x70, + 0x1f, 0x77, 0x86, 0x30, + 0x0f, 0xff, 0x07, 0x30, + 0x07, 0xfe, 0x07, 0x38, + 0x03, 0xfc, 0x23, 0x38, + 0x01, 0xf8, 0x63, 0x18, + 0x01, 0xf8, 0x63, 0x18, + 0x03, 0xfc, 0x23, 0x38, + 0x07, 0xfe, 0x07, 0x38, + 0x0f, 0xff, 0x07, 0x30, + 0x1f, 0x77, 0x86, 0x70, + 0x3e, 0x73, 0xc0, 0x70, + 0x7c, 0x71, 0xe0, 0xe0, + 0xf8, 0x73, 0xe0, 0xc0, + 0x70, 0x77, 0xc0, 0x00, + 0x20, 0x7f, 0x80, 0x00, + 0x00, 0x7f, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising = { + .header.always_zero = 0, + .header.w = 29, + .header.h = 35, + .data_size = 148, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising_1.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising_1.c new file mode 100644 index 00000000000..9fdc8e55a47 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising_1.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_1 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_1 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_1 uint8_t bluetooth_advertising_1_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xc0, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xe0, + 0xf8, 0xf3, 0xc1, 0xc0, 0x7f, 0xff, 0xe0, + 0x7c, 0xf3, 0xe0, 0xc0, 0xff, 0xff, 0xf0, + 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0x8f, 0xf8, + 0x1f, 0xff, 0x84, 0x61, 0xfe, 0x0f, 0xf8, + 0x0f, 0xff, 0x0e, 0x71, 0xfe, 0x0f, 0xf8, + 0x07, 0xfe, 0x06, 0x31, 0xff, 0xcf, 0xfc, + 0x03, 0xfc, 0x27, 0x33, 0xff, 0xcf, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xff, 0xcf, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xff, 0xcf, 0xfc, + 0x03, 0xfc, 0x27, 0x33, 0xff, 0xcf, 0xfc, + 0x07, 0xfe, 0x06, 0x31, 0xff, 0xcf, 0xfc, + 0x0f, 0xff, 0x0e, 0x71, 0xff, 0xcf, 0xf8, + 0x1f, 0xff, 0x84, 0x61, 0xff, 0xcf, 0xf8, + 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0xcf, 0xf8, + 0x7c, 0xf3, 0xe1, 0xc0, 0xff, 0xff, 0xf0, + 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xe0, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xe0, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x80, + 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising_1 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_1_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising_2.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising_2.c new file mode 100644 index 00000000000..a0c4345d99b --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising_2.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_2 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_2 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_2 uint8_t bluetooth_advertising_2_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfe, 0x00, 0x00, 0x03, 0xfc, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x60, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xc0, + 0xf0, 0xf7, 0xc0, 0x80, 0x7f, 0xff, 0xe0, + 0x78, 0xf3, 0xe1, 0xc0, 0x7f, 0xff, 0xf0, + 0x3c, 0xf3, 0xc0, 0xe0, 0xff, 0x0f, 0xf0, + 0x1e, 0xf7, 0x84, 0xe1, 0xfe, 0x07, 0xf8, + 0x0f, 0xff, 0x0e, 0x71, 0xfc, 0x63, 0xf8, + 0x07, 0xfe, 0x0e, 0x71, 0xff, 0xf3, 0xfc, + 0x03, 0xfc, 0x06, 0x33, 0xff, 0xe3, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xff, 0xe7, 0xfc, + 0x01, 0xf8, 0xe7, 0x33, 0xff, 0xc7, 0xfc, + 0x01, 0xfc, 0x67, 0x33, 0xff, 0x8f, 0xfc, + 0x03, 0xfe, 0x06, 0x33, 0xff, 0x1f, 0xfc, + 0x07, 0xff, 0x0e, 0x71, 0xfe, 0x3f, 0xfc, + 0x0f, 0xff, 0x8e, 0x61, 0xfc, 0x03, 0xf8, + 0x1e, 0xf7, 0xc0, 0xe1, 0xfc, 0x03, 0xf8, + 0x3c, 0xf3, 0xe0, 0xc0, 0xff, 0xff, 0xf0, + 0x78, 0xf3, 0xe1, 0xc0, 0x7f, 0xff, 0xf0, + 0xf0, 0xf7, 0xc0, 0x80, 0x7f, 0xff, 0xe0, + 0x60, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xc0, + 0x00, 0xff, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0xfe, 0x00, 0x00, 0x03, 0xfc, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising_2 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_2_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising_3.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising_3.c new file mode 100644 index 00000000000..3e70f082868 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising_3.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_3 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_3 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_3 uint8_t bluetooth_advertising_3_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xc0, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xe0, + 0xf8, 0xf3, 0xc1, 0xc0, 0x7f, 0xff, 0xf0, + 0x7c, 0xf3, 0xe0, 0xc0, 0xff, 0x9f, 0xf0, + 0x3e, 0xf7, 0xc0, 0xe0, 0xfe, 0x07, 0xf8, + 0x1f, 0xff, 0x84, 0x61, 0xfe, 0x03, 0xf8, + 0x0f, 0xff, 0x0e, 0x71, 0xfe, 0xe3, 0xfc, + 0x07, 0xfe, 0x06, 0x31, 0xff, 0xe3, 0xfc, + 0x03, 0xfc, 0x27, 0x33, 0xff, 0x87, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xff, 0x87, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xff, 0x83, 0xfc, + 0x03, 0xfc, 0x27, 0x33, 0xff, 0xf3, 0xfc, + 0x07, 0xfe, 0x06, 0x31, 0xfe, 0xf3, 0xfc, + 0x0f, 0xff, 0x0e, 0x71, 0xfc, 0x63, 0xfc, + 0x1f, 0xff, 0x84, 0x61, 0xfe, 0x03, 0xf8, + 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0x0f, 0xf8, + 0x7c, 0xf3, 0xe1, 0xc0, 0xff, 0xff, 0xf0, + 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xf0, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xe0, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xc0, + 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising_3 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_3_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising_4.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising_4.c new file mode 100644 index 00000000000..3e8441f7b37 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising_4.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_4 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_4 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_4 uint8_t bluetooth_advertising_4_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xc0, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xe0, + 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xe0, + 0x7c, 0xf3, 0xe0, 0xc0, 0xff, 0xff, 0xf0, + 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0xcf, 0xf8, + 0x1f, 0xff, 0x84, 0x61, 0xff, 0x8f, 0xf8, + 0x0f, 0xff, 0x0e, 0x71, 0xff, 0x0f, 0xf8, + 0x07, 0xfe, 0x06, 0x31, 0xff, 0x0f, 0xfc, + 0x03, 0xfc, 0x27, 0x31, 0xfe, 0x4f, 0xfc, + 0x01, 0xf8, 0x67, 0x31, 0xfc, 0x4f, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xfc, 0xcf, 0xfc, + 0x03, 0xfc, 0x27, 0x31, 0xf8, 0x07, 0xfc, + 0x07, 0xfe, 0x06, 0x31, 0xf8, 0x03, 0xfc, + 0x0f, 0xff, 0x0e, 0x71, 0xf8, 0x07, 0xf8, + 0x1f, 0xff, 0x84, 0x61, 0xff, 0xcf, 0xf8, + 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0xcf, 0xf8, + 0x7c, 0xf3, 0xe1, 0xc0, 0xff, 0xff, 0xf0, + 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xe0, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xc0, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x80, + 0x00, 0xfe, 0x00, 0x00, 0x07, 0xff, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xf8, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising_4 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_4_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising_5.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising_5.c new file mode 100644 index 00000000000..3b24c9d81e8 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_advertising_5.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_5 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_5 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_5 uint8_t bluetooth_advertising_5_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x80, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xe0, + 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xe0, + 0x7c, 0xf3, 0xe0, 0xe0, 0xff, 0xff, 0xf0, + 0x3e, 0xf7, 0xc0, 0xe1, 0xfe, 0x07, 0xf8, + 0x1f, 0xff, 0x84, 0x61, 0xfe, 0x07, 0xf8, + 0x0f, 0xff, 0x0e, 0x71, 0xfc, 0x7f, 0xf8, + 0x07, 0xfe, 0x06, 0x33, 0xfc, 0x7f, 0xfc, + 0x03, 0xfc, 0x27, 0x33, 0xfc, 0x07, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xfc, 0x03, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xff, 0x63, 0xfc, + 0x03, 0xfc, 0x27, 0x33, 0xff, 0xf3, 0xfc, + 0x07, 0xfe, 0x06, 0x33, 0xfe, 0xf3, 0xfc, + 0x0f, 0xff, 0x0e, 0x71, 0xfc, 0x63, 0xf8, + 0x1f, 0xff, 0x84, 0x61, 0xfe, 0x07, 0xf8, + 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0x0f, 0xf8, + 0x7c, 0xf3, 0xe1, 0xc0, 0xff, 0xff, 0xf0, + 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xe0, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xc0, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x80, + 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xf8, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising_5 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_5_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_1.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_1.c new file mode 100644 index 00000000000..1cb545aa2b2 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_1.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_1 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_1 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_1 uint8_t bluetooth_connected_1_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0xc0, + 0x78, 0x77, 0xc0, 0x00, 0x3f, 0xff, 0xe0, + 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, + 0x3e, 0x71, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x1f, 0x73, 0xc0, 0x00, 0xff, 0x8f, 0xf8, + 0x0f, 0xff, 0x80, 0x01, 0xfe, 0x0f, 0xf8, + 0x87, 0xff, 0x08, 0x01, 0xfe, 0x0f, 0xf8, + 0xc3, 0xfe, 0x18, 0x01, 0xff, 0xcf, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xff, 0xcf, 0xfc, + 0xf0, 0xf8, 0x78, 0x03, 0xff, 0xcf, 0xfc, + 0xf0, 0xfc, 0x78, 0x03, 0xff, 0xcf, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xff, 0xcf, 0xfc, + 0xc3, 0xfe, 0x18, 0x01, 0xff, 0xcf, 0xfc, + 0x87, 0xff, 0x08, 0x01, 0xff, 0xcf, 0xf8, + 0x0f, 0xff, 0x80, 0x01, 0xff, 0xcf, 0xf8, + 0x1e, 0x73, 0xc0, 0x00, 0xff, 0xcf, 0xf8, + 0x3c, 0x71, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x78, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, + 0x78, 0x77, 0xc0, 0x00, 0x3f, 0xff, 0xe0, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_1 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_1_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_2.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_2.c new file mode 100644 index 00000000000..c5775a61167 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_2.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_2 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_2 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_2 uint8_t bluetooth_connected_2_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x03, 0xfc, 0x00, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0xc0, + 0x78, 0x73, 0xc0, 0x00, 0x7f, 0xff, 0xe0, + 0x7c, 0x71, 0xe0, 0x00, 0x7f, 0xff, 0xf0, + 0x3e, 0x73, 0xe0, 0x00, 0xff, 0x0f, 0xf0, + 0x1f, 0x77, 0xc0, 0x01, 0xfe, 0x07, 0xf8, + 0x0f, 0xff, 0x80, 0x01, 0xfc, 0x63, 0xf8, + 0x87, 0xff, 0x08, 0x01, 0xff, 0xf3, 0xfc, + 0xc3, 0xfe, 0x18, 0x03, 0xff, 0xe3, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xff, 0xe7, 0xfc, + 0xf0, 0xf8, 0x78, 0x03, 0xff, 0xc7, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xff, 0x8f, 0xfc, + 0xc3, 0xfe, 0x18, 0x03, 0xff, 0x1f, 0xfc, + 0x87, 0xff, 0x08, 0x01, 0xfe, 0x3f, 0xfc, + 0x0f, 0xff, 0x80, 0x01, 0xfc, 0x03, 0xf8, + 0x1f, 0x77, 0xc0, 0x01, 0xfc, 0x03, 0xf8, + 0x3e, 0x73, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x7c, 0x71, 0xe0, 0x00, 0x7f, 0xff, 0xf0, + 0x78, 0x73, 0xc0, 0x00, 0x7f, 0xff, 0xe0, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0xc0, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x03, 0xfc, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_2 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_2_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_3.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_3.c new file mode 100644 index 00000000000..111b9d320a9 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_3.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_3 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_3 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_3 uint8_t bluetooth_connected_3_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x03, 0xfc, 0x00, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0xc0, + 0x78, 0x77, 0xc0, 0x00, 0x7f, 0xff, 0xe0, + 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xf0, + 0x3e, 0x71, 0xe0, 0x00, 0xff, 0x9f, 0xf0, + 0x1f, 0x73, 0xc0, 0x01, 0xfe, 0x07, 0xf8, + 0x0f, 0xff, 0x80, 0x01, 0xfc, 0x03, 0xf8, + 0x87, 0xff, 0x08, 0x01, 0xfe, 0xe3, 0xfc, + 0xc3, 0xfe, 0x18, 0x03, 0xff, 0xe3, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xff, 0x87, 0xfc, + 0xf0, 0xf8, 0x78, 0x03, 0xff, 0x87, 0xfc, + 0xf0, 0xfc, 0x78, 0x03, 0xff, 0x83, 0xfc, + 0xe1, 0xfe, 0x38, 0x03, 0xff, 0xf3, 0xfc, + 0xc3, 0xff, 0x18, 0x03, 0xfe, 0xf3, 0xfc, + 0x87, 0xff, 0x88, 0x01, 0xfc, 0x63, 0xf8, + 0x0f, 0xf7, 0xc0, 0x01, 0xfe, 0x03, 0xf8, + 0x1f, 0x73, 0xe0, 0x01, 0xff, 0x0f, 0xf8, + 0x3e, 0x71, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, + 0x78, 0x77, 0xc0, 0x00, 0x3f, 0xff, 0xe0, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x01, 0xf8, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_3 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_3_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_4.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_4.c new file mode 100644 index 00000000000..3b2db361515 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_4.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_4 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_4 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_4 uint8_t bluetooth_connected_4_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x01, 0xf8, 0x00, + 0x00, 0x7f, 0x00, 0x00, 0x07, 0xff, 0x00, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, + 0x78, 0x77, 0xc0, 0x00, 0x3f, 0xff, 0xe0, + 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, + 0x3e, 0x71, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x1f, 0x73, 0xc0, 0x00, 0xff, 0xcf, 0xf8, + 0x0f, 0xff, 0x80, 0x01, 0xff, 0x8f, 0xf8, + 0x87, 0xff, 0x08, 0x01, 0xff, 0x0f, 0xf8, + 0xc3, 0xfe, 0x18, 0x01, 0xff, 0x0f, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xfe, 0x4f, 0xfc, + 0xf0, 0xf8, 0x78, 0x03, 0xfc, 0x4f, 0xfc, + 0xf0, 0xfc, 0x78, 0x03, 0xfc, 0xcf, 0xfc, + 0xe1, 0xfe, 0x38, 0x03, 0xf8, 0xc7, 0xfc, + 0xc3, 0xff, 0x18, 0x01, 0xf8, 0x03, 0xfc, + 0x87, 0xff, 0x88, 0x01, 0xf8, 0x03, 0xf8, + 0x0f, 0xf7, 0xc0, 0x01, 0xff, 0xcf, 0xf8, + 0x1f, 0x73, 0xe0, 0x00, 0xff, 0xcf, 0xf8, + 0x3e, 0x71, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, + 0x78, 0x77, 0xc0, 0x00, 0x3f, 0xff, 0xe0, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x01, 0xf8, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_4 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_4_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_5.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_5.c new file mode 100644 index 00000000000..bab117b89dc --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_5.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_5 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_5 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_5 uint8_t bluetooth_connected_5_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, + 0x78, 0x77, 0xc0, 0x00, 0x3f, 0xff, 0xe0, + 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, + 0x3e, 0x71, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x1f, 0x73, 0xc0, 0x01, 0xfe, 0x07, 0xf8, + 0x0f, 0xff, 0x80, 0x01, 0xfe, 0x07, 0xf8, + 0x87, 0xff, 0x08, 0x01, 0xfc, 0x7f, 0xf8, + 0xc3, 0xfe, 0x18, 0x03, 0xfc, 0x7f, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xfc, 0x07, 0xfc, + 0xf0, 0xf8, 0x78, 0x03, 0xfc, 0x03, 0xfc, + 0xf0, 0xfc, 0x78, 0x03, 0xff, 0x63, 0xfc, + 0xe1, 0xfe, 0x38, 0x03, 0xff, 0xf3, 0xfc, + 0xc3, 0xff, 0x18, 0x03, 0xfe, 0xf3, 0xfc, + 0x87, 0xff, 0x88, 0x01, 0xfc, 0x63, 0xf8, + 0x0f, 0xf7, 0xc0, 0x01, 0xfe, 0x07, 0xf8, + 0x1e, 0x73, 0xc0, 0x00, 0xff, 0x0f, 0xf8, + 0x3c, 0x71, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, + 0x78, 0x77, 0xc0, 0x00, 0x3f, 0xff, 0xc0, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x01, 0xf8, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_5 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_5_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_right.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_right.c new file mode 100644 index 00000000000..1e637bdf29a --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_connected_right.c @@ -0,0 +1,69 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_RIGHT +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_RIGHT +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_RIGHT uint8_t bluetooth_connected_right_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3f, 0x00, 0x00, 0x03, 0xf8, 0x00, + 0x00, 0x3f, 0x80, 0x00, 0x0f, 0xfe, 0x00, + 0x10, 0x3f, 0xc0, 0x00, 0x3f, 0xff, 0x80, + 0x38, 0x3b, 0xe0, 0x00, 0x7f, 0xff, 0xc0, + 0x7c, 0x39, 0xf0, 0x00, 0xff, 0xff, 0xe0, + 0x3e, 0x38, 0xf0, 0x01, 0xff, 0xff, 0xf0, + 0x1f, 0x39, 0xe0, 0x01, 0xff, 0xfe, 0x30, + 0x0f, 0xbb, 0xc0, 0x03, 0xff, 0xfc, 0x38, + 0x87, 0xff, 0x84, 0x03, 0xff, 0xf8, 0x38, + 0xc3, 0xff, 0x0c, 0x07, 0xff, 0xf0, 0x3c, + 0xe1, 0xfe, 0x1c, 0x07, 0xcf, 0xe0, 0x7c, + 0xf0, 0xfc, 0x3c, 0x07, 0x87, 0xc0, 0xfc, + 0xf0, 0xfc, 0x3c, 0x07, 0x83, 0x81, 0xfc, + 0xe1, 0xfe, 0x1c, 0x07, 0x81, 0x03, 0xfc, + 0xc3, 0xff, 0x0c, 0x07, 0xc0, 0x07, 0xfc, + 0x87, 0xff, 0x84, 0x07, 0xe0, 0x0f, 0xfc, + 0x0f, 0xbb, 0xc0, 0x03, 0xf0, 0x1f, 0xf8, + 0x1f, 0x39, 0xe0, 0x03, 0xf8, 0x3f, 0xf8, + 0x3e, 0x38, 0xf0, 0x01, 0xfc, 0xff, 0xf0, + 0x7c, 0x39, 0xf0, 0x01, 0xff, 0xff, 0xf0, + 0x38, 0x3b, 0xe0, 0x00, 0xff, 0xff, 0xe0, + 0x10, 0x3f, 0xc0, 0x00, 0x7f, 0xff, 0xc0, + 0x00, 0x3f, 0x80, 0x00, 0x3f, 0xff, 0x80, + 0x00, 0x3f, 0x00, 0x00, 0x0f, 0xfe, 0x00, + 0x00, 0x3e, 0x00, 0x00, 0x03, 0xf8, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_right = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 253, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_right_map, +}; + diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_disconnected.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_disconnected.c new file mode 100644 index 00000000000..05f81393f52 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/bluetooth_disconnected.c @@ -0,0 +1,68 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_DISCONNECTED +#define LV_ATTRIBUTE_IMG_BLUETOOTH_DISCONNECTED +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BLUETOOTH_DISCONNECTED uint8_t bluetooth_disconnected_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3f, 0x00, 0x00, 0x03, 0xf8, 0x00, + 0x00, 0x3f, 0x80, 0x00, 0x0f, 0xfe, 0x00, + 0x10, 0x3f, 0xc0, 0x00, 0x3f, 0xff, 0x80, + 0x38, 0x3b, 0xe0, 0x00, 0x7f, 0xff, 0xc0, + 0x7c, 0x39, 0xf0, 0x00, 0xff, 0xff, 0xe0, + 0x3e, 0x38, 0xf0, 0x01, 0xff, 0xff, 0xf0, + 0x1f, 0x39, 0xe0, 0x01, 0xe3, 0xf8, 0xf0, + 0x0f, 0xbb, 0xc0, 0x03, 0xe1, 0xf0, 0xf8, + 0x07, 0xff, 0x80, 0x03, 0xe0, 0xe0, 0xf8, + 0x03, 0xff, 0x00, 0x07, 0xf0, 0x01, 0xfc, + 0x01, 0xfe, 0x00, 0x07, 0xf8, 0x03, 0xfc, + 0x00, 0xfc, 0x00, 0x07, 0xfc, 0x07, 0xfc, + 0x00, 0xfc, 0x00, 0x07, 0xfc, 0x07, 0xfc, + 0x01, 0xfe, 0x00, 0x07, 0xfc, 0x07, 0xfc, + 0x03, 0xff, 0x00, 0x07, 0xf8, 0x03, 0xfc, + 0x07, 0xff, 0x80, 0x07, 0xf0, 0x01, 0xfc, + 0x0f, 0xbb, 0xc0, 0x03, 0xe0, 0xe0, 0xf8, + 0x1f, 0x39, 0xe0, 0x03, 0xe1, 0xf0, 0xf8, + 0x3e, 0x38, 0xf0, 0x01, 0xe3, 0xf8, 0xf0, + 0x7c, 0x39, 0xf0, 0x01, 0xff, 0xff, 0xf0, + 0x38, 0x3b, 0xe0, 0x00, 0xff, 0xff, 0xe0, + 0x10, 0x3f, 0xc0, 0x00, 0x7f, 0xff, 0xc0, + 0x00, 0x3f, 0x80, 0x00, 0x3f, 0xff, 0x80, + 0x00, 0x3f, 0x00, 0x00, 0x0f, 0xfe, 0x00, + 0x00, 0x3e, 0x00, 0x00, 0x03, 0xf8, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_disconnected = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 253, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_disconnected_map, +}; + diff --git a/app/boards/arm/nrfmacro/epd_screen/master/icons/layers.c b/app/boards/arm/nrfmacro/epd_screen/master/icons/layers.c new file mode 100644 index 00000000000..9c0b53f7dbf --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/icons/layers.c @@ -0,0 +1,45 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_LAYERS +#define LV_ATTRIBUTE_IMG_LAYERS +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_LAYERS uint8_t layers_map[] = { + 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x30, 0x0f, 0x18, 0xdf, 0xdf, 0xc0, 0x04, 0x00, + 0x00, 0x80, 0x30, 0x19, 0x98, 0xd8, 0x18, 0xe0, 0x0e, 0x00, + 0x00, 0x80, 0x30, 0x30, 0xd8, 0xd8, 0x18, 0xe0, 0x1f, 0x00, + 0x00, 0x80, 0x30, 0x30, 0xcf, 0x9f, 0xd9, 0xc0, 0x04, 0x00, + 0x00, 0x80, 0x30, 0x3f, 0xc7, 0x18, 0x1f, 0x80, 0x04, 0x00, + 0x03, 0xe0, 0x30, 0x39, 0xc6, 0x18, 0x1b, 0x80, 0x04, 0x00, + 0x01, 0xc0, 0x3f, 0xb0, 0xc6, 0x1f, 0xd9, 0xc0, 0x04, 0x00, + 0x00, 0x80, 0x3f, 0xb0, 0xc6, 0x1f, 0xd8, 0xe0, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t layers = { + .header.always_zero = 0, + .header.w = 78, + .header.h = 12, + .data_size = 128, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = layers_map, +}; + diff --git a/app/boards/arm/nrfmacro/epd_screen/master/layer_status.c b/app/boards/arm/nrfmacro/epd_screen/master/layer_status.c new file mode 100644 index 00000000000..92022629a12 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/layer_status.c @@ -0,0 +1,102 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); +#include +#include "layer_status.h" +#include +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); +static lv_style_t label_style; + +static bool style_initialized = false; + +K_MUTEX_DEFINE(layer_status_mutex); + +struct { + uint8_t index; + const char *label; +} layer_status_state; + +void layer_status_init() { + if (style_initialized) { + return; + } + style_initialized = true; + lv_style_init(&label_style); + lv_style_set_text_color(&label_style, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_style_set_text_font(&label_style, LV_STATE_DEFAULT, &lv_font_montserrat_16); + lv_style_set_text_letter_space(&label_style, LV_STATE_DEFAULT, 1); + lv_style_set_text_line_space(&label_style, LV_STATE_DEFAULT, 1); + +} + +void set_layer_symbol(lv_obj_t *label) { + + k_mutex_lock(&layer_status_mutex, K_FOREVER); + const char *layer_label = layer_status_state.label; + uint8_t active_layer_index = layer_status_state.index; + k_mutex_unlock(&layer_status_mutex); + + //LOG_DBG("Layer Label: %s", layer_label); + + if (layer_label == NULL) { + char text[6] = {}; + + sprintf(text, " %i", active_layer_index); + + lv_label_set_text(label, text); + } else { + lv_label_set_text(label, layer_label); + } +} + +static void update_state() { + k_mutex_lock(&layer_status_mutex, K_FOREVER); + layer_status_state.index = zmk_keymap_highest_layer_active(); + layer_status_state.label = zmk_keymap_layer_label(layer_status_state.index); + LOG_DBG("Layer changed to %i", layer_status_state.index); + + k_mutex_unlock(&layer_status_mutex); +} + +int zmk_widget_layer_status_init(struct zmk_widget_layer_status *widget, lv_obj_t *parent) { + layer_status_init(); + update_state(); + widget->obj = lv_label_create(parent, NULL); + lv_obj_add_style(widget->obj, LV_LABEL_PART_MAIN, &label_style); + set_layer_symbol(widget->obj); + sys_slist_append(&widgets, &widget->node); + + return 0; +} + +lv_obj_t *zmk_widget_layer_status_obj(struct zmk_widget_layer_status *widget) { + return widget->obj; +} + +void layer_status_update_cb(struct k_work *work) { + struct zmk_widget_layer_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_layer_symbol(widget->obj); } +} + +K_WORK_DEFINE(layer_status_update_work, layer_status_update_cb); + +int layer_status_listener(const zmk_event_t *eh) { + update_state();; + + k_work_submit_to_queue(zmk_display_work_q(), &layer_status_update_work); + return 0; +} + +ZMK_LISTENER(widget_layer_status, layer_status_listener) +ZMK_SUBSCRIPTION(widget_layer_status, zmk_layer_state_changed); \ No newline at end of file diff --git a/app/boards/arm/nrfmacro/epd_screen/master/layer_status.h b/app/boards/arm/nrfmacro/epd_screen/master/layer_status.h new file mode 100644 index 00000000000..2616ad225d0 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/layer_status.h @@ -0,0 +1,20 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#pragma once + +#include +#include + +struct zmk_widget_layer_status { + sys_snode_t node; + lv_obj_t *obj; + //lv_obj_t *obj2; +}; + +int zmk_widget_layer_status_init(struct zmk_widget_layer_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_layer_status_obj(struct zmk_widget_layer_status *widget); \ No newline at end of file diff --git a/app/boards/arm/nrfmacro/epd_screen/master/output_status.c b/app/boards/arm/nrfmacro/epd_screen/master/output_status.c new file mode 100644 index 00000000000..a67ad0b3bba --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/output_status.c @@ -0,0 +1,183 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include "output_status.h" +#include +#include +#include +#include +#include +#include +#include + +LV_IMG_DECLARE(bluetooth_disconnected); +LV_IMG_DECLARE(bluetooth_connected_1); +LV_IMG_DECLARE(bluetooth_connected_2); +LV_IMG_DECLARE(bluetooth_connected_3); +LV_IMG_DECLARE(bluetooth_connected_4); +LV_IMG_DECLARE(bluetooth_connected_5); +LV_IMG_DECLARE(bluetooth_advertising_1); +LV_IMG_DECLARE(bluetooth_advertising_2); +LV_IMG_DECLARE(bluetooth_advertising_3); +LV_IMG_DECLARE(bluetooth_advertising_4); +LV_IMG_DECLARE(bluetooth_advertising_5); +LV_IMG_DECLARE(USB_connected); + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); +static lv_style_t label_style; + +static bool style_initialized = false; + +K_MUTEX_DEFINE(output_status_mutex); + +struct { + enum zmk_endpoint selected_endpoint; + bool active_profile_connected; + bool active_profile_bonded; + uint8_t active_profile_index; +} output_status_state; + +void output_status_init() { + if (style_initialized) { + return; + } + + style_initialized = true; + lv_style_init(&label_style); + lv_style_set_text_color(&label_style, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_style_set_text_font(&label_style, LV_STATE_DEFAULT, &lv_font_montserrat_26); + lv_style_set_text_letter_space(&label_style, LV_STATE_DEFAULT, 1); + lv_style_set_text_line_space(&label_style, LV_STATE_DEFAULT, 1); +} + +void set_status_symbol(lv_obj_t *icon) { + + k_mutex_lock(&output_status_mutex, K_FOREVER); + enum zmk_endpoint selected_endpoint = output_status_state.selected_endpoint; + bool active_profile_connected = output_status_state.active_profile_connected; + bool active_profie_bonded = output_status_state.active_profile_bonded; + uint8_t active_profile_index = output_status_state.active_profile_index; + k_mutex_unlock(&output_status_mutex); + + switch (selected_endpoint) { + case ZMK_ENDPOINT_USB: + lv_img_set_src(icon, &USB_connected); + break; + case ZMK_ENDPOINT_BLE: + if (active_profie_bonded) { + if (active_profile_connected) { + //sprintf(text, LV_SYMBOL_BLUETOOTH "%i " LV_SYMBOL_OK, active_profile_index); + switch (active_profile_index) { + case 0: + lv_img_set_src(icon, &bluetooth_connected_1); + break; + case 1: + lv_img_set_src(icon, &bluetooth_connected_2); + break; + case 2: + lv_img_set_src(icon, &bluetooth_connected_3); + break; + case 3: + lv_img_set_src(icon, &bluetooth_connected_4); + break; + case 4: + lv_img_set_src(icon, &bluetooth_connected_5); + break; + } + } else { + //sprintf(text, LV_SYMBOL_BLUETOOTH "%i " LV_SYMBOL_CLOSE, active_profile_index); + lv_img_set_src(icon, &bluetooth_disconnected); + } + } else { + //sprintf(text, LV_SYMBOL_BLUETOOTH "%i " LV_SYMBOL_SETTINGS, active_profile_index); + switch (active_profile_index) { + case 0: + lv_img_set_src(icon, &bluetooth_advertising_1); + break; + case 1: + lv_img_set_src(icon, &bluetooth_advertising_2); + break; + case 2: + lv_img_set_src(icon, &bluetooth_advertising_3); + break; + case 3: + lv_img_set_src(icon, &bluetooth_advertising_4); + break; + case 4: + lv_img_set_src(icon, &bluetooth_advertising_5); + break; + } + } + break; + } + + //lv_label_set_text(label, text); +} + +static void update_state() { + k_mutex_lock(&output_status_mutex, K_FOREVER); + output_status_state.selected_endpoint = zmk_endpoints_selected(); + output_status_state.active_profile_connected = zmk_ble_active_profile_is_connected(); + output_status_state.active_profile_bonded = !zmk_ble_active_profile_is_open(); + output_status_state.active_profile_index = zmk_ble_active_profile_index(); + k_mutex_unlock(&output_status_mutex); +} + +int zmk_widget_output_status_init(struct zmk_widget_output_status *widget, lv_obj_t *parent) { + output_status_init(); + update_state(); + //widget->obj = lv_label_create(parent, NULL); + widget->obj = lv_img_create(parent, NULL); + + set_status_symbol(widget->obj); + + sys_slist_append(&widgets, &widget->node); + + return 0; +} + +lv_obj_t *zmk_widget_output_status_obj(struct zmk_widget_output_status *widget) { + return widget->obj; +} + +void output_status_update_cb(struct k_work *work) { + struct zmk_widget_output_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_status_symbol(widget->obj); } +} + +K_WORK_DEFINE(output_status_update_work, output_status_update_cb); + +int output_status_listener(const zmk_event_t *eh) { + + + // Be sure we have widgets initialized before doing any work, + // since the status event can fire before display code inits. + if (!style_initialized) { + return ZMK_EV_EVENT_BUBBLE; + } + + update_state(); + + k_work_submit_to_queue(zmk_display_work_q(), &output_status_update_work); + return ZMK_EV_EVENT_BUBBLE; +} + +ZMK_LISTENER(widget_output_status, output_status_listener) +ZMK_SUBSCRIPTION(widget_output_status, zmk_endpoint_selection_changed); +#if defined(CONFIG_USB) +ZMK_SUBSCRIPTION(widget_output_status, zmk_usb_conn_state_changed); +#endif +#if defined(CONFIG_ZMK_BLE) +ZMK_SUBSCRIPTION(widget_output_status, zmk_ble_active_profile_changed); +#endif diff --git a/app/boards/arm/nrfmacro/epd_screen/master/output_status.h b/app/boards/arm/nrfmacro/epd_screen/master/output_status.h new file mode 100644 index 00000000000..d10018b15e3 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/output_status.h @@ -0,0 +1,19 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#pragma once + +#include +#include + +struct zmk_widget_output_status { + sys_snode_t node; + lv_obj_t *obj; +}; + +int zmk_widget_output_status_init(struct zmk_widget_output_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_output_status_obj(struct zmk_widget_output_status *widget); \ No newline at end of file diff --git a/app/boards/arm/nrfmacro/epd_screen/master/status_screen.c b/app/boards/arm/nrfmacro/epd_screen/master/status_screen.c new file mode 100644 index 00000000000..daff751d9c4 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/master/status_screen.c @@ -0,0 +1,60 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include "battery_status.h" +#include "output_status.h" +#include "layer_status.h" +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +LV_IMG_DECLARE(layers); + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_BATTERY_STATUS) +static struct zmk_widget_battery_status battery_status_widget; +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS) +static struct zmk_widget_output_status output_status_widget; +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_LAYER_STATUS) +static struct zmk_widget_layer_status layer_status_widget; +#endif + +lv_obj_t *zmk_display_status_screen() { + + lv_obj_t *screen; + screen = lv_obj_create(NULL, NULL); + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_BATTERY_STATUS) + zmk_widget_battery_status_init(&battery_status_widget, screen); + lv_obj_align(zmk_widget_battery_status_obj(&battery_status_widget), NULL, LV_ALIGN_IN_TOP_MID, 0, 2); +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS) + zmk_widget_output_status_init(&output_status_widget, screen); + lv_obj_align(zmk_widget_output_status_obj(&output_status_widget), NULL, LV_ALIGN_IN_TOP_MID, 0, 41); +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_LAYER_STATUS) + //lv_style_set_pad_inner(&layerstyle, LV_STATE_DEFAULT, 12); + //lv_obj_add_style(&layer_status_widget, LV_WIDGET_PART_MAIN, &layerstyle); + zmk_widget_layer_status_init(&layer_status_widget, screen); + lv_obj_align(zmk_widget_layer_status_obj(&layer_status_widget), NULL, LV_ALIGN_IN_BOTTOM_MID, 0, -5); + + lv_obj_t * LayersHeading; + LayersHeading = lv_img_create(screen, NULL); + lv_obj_align(LayersHeading, NULL, LV_ALIGN_IN_BOTTOM_MID, 8, 5); + lv_img_set_src(LayersHeading, &layers); +#endif + + lv_refr_now(NULL); + + return screen; +} diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/CMakeLists.txt b/app/boards/arm/nrfmacro/epd_screen/slave/CMakeLists.txt new file mode 100644 index 00000000000..b876a47de2e --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/slave/CMakeLists.txt @@ -0,0 +1,33 @@ +# +# Copyright (c) 2021 Darryl deHaan +# SPDX-License-Identifier: MIT +# + +zephyr_library() + +zephyr_library_include_directories(${ZEPHYR_LVGL_MODULE_DIR}) +zephyr_library_include_directories(${ZEPHYR_BASE}/lib/gui/lvgl/) +zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) + +zephyr_library_sources(status_screen.c) +zephyr_library_sources_ifdef(CONFIG_CUSTOM_WIDGET_BATTERY_STATUS battery_status.c) +zephyr_library_sources_ifdef(CONFIG_CUSTOM_WIDGET_PERIPHERAL_STATUS peripheral_status.c) + +add_compile_definitions(LV_LVGL_H_INCLUDE_SIMPLE) +if (CONFIG_NRFMACRO_SCREEN_MARK_LOGO) +zephyr_library_sources(icons/${CONFIG_NRFMACRO_MARKLOGO_NAME}) +endif() + +if (CONFIG_NRFMACRO_SCREEN_STANDARD_LOGO) +zephyr_library_sources(icons/stdlogo.c) +endif() + +if (CONFIG_NRFMACRO_SCREEN_CUSTOM_LOGO) +if(ZMK_CONFIG) + zephyr_library_sources(${ZMK_CONFIG}/icons/customlogo.c) +else() + zephyr_library_sources(icons/customlogo.c) +endif() +endif() + diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/battery_status.c b/app/boards/arm/nrfmacro/epd_screen/slave/battery_status.c new file mode 100644 index 00000000000..e4520965c68 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/slave/battery_status.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include "battery_status.h" +#include +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct battery_status_state { + uint8_t level; +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + bool usb_present; +#endif +}; + +static void set_battery_symbol(lv_obj_t *label, struct battery_status_state state) { + char text[2] = " "; + + uint8_t level = state.level; + +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + if (state.usb_present) { + strcpy(text, LV_SYMBOL_CHARGE); + } +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + + if (level > 95) { + strcat(text, LV_SYMBOL_BATTERY_FULL); + } else if (level > 65) { + strcat(text, LV_SYMBOL_BATTERY_3); + } else if (level > 35) { + strcat(text, LV_SYMBOL_BATTERY_2); + } else if (level > 5) { + strcat(text, LV_SYMBOL_BATTERY_1); + } else { + strcat(text, LV_SYMBOL_BATTERY_EMPTY); + } + lv_label_set_text(label, text); +} + +void battery_status_update_cb(struct battery_status_state state) { + struct zmk_widget_battery_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_battery_symbol(widget->obj, state); } +} + +static struct battery_status_state battery_status_get_state(const zmk_event_t *eh) { + return (struct battery_status_state) { + .level = bt_bas_get_battery_level(), +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + .usb_present = zmk_usb_is_powered(), +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + }; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_battery_status, struct battery_status_state, + battery_status_update_cb, battery_status_get_state) + +ZMK_SUBSCRIPTION(widget_battery_status, zmk_battery_state_changed); +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) +ZMK_SUBSCRIPTION(widget_battery_status, zmk_usb_conn_state_changed); +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + +int zmk_widget_battery_status_init(struct zmk_widget_battery_status *widget, lv_obj_t *parent) { + widget->obj = lv_label_create(parent, NULL); + + lv_obj_set_size(widget->obj, 43, 15); + + sys_slist_append(&widgets, &widget->node); + + widget_battery_status_init(); + return 0; +} + +lv_obj_t *zmk_widget_battery_status_obj(struct zmk_widget_battery_status *widget) { + return widget->obj; +} diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/battery_status.h b/app/boards/arm/nrfmacro/epd_screen/slave/battery_status.h new file mode 100644 index 00000000000..b87e87ee6d4 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/slave/battery_status.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +struct zmk_widget_battery_status { + sys_snode_t node; + lv_obj_t *obj; +}; + +int zmk_widget_battery_status_init(struct zmk_widget_battery_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_battery_status_obj(struct zmk_widget_battery_status *widget); \ No newline at end of file diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/cornepro-marklogo.c b/app/boards/arm/nrfmacro/epd_screen/slave/icons/cornepro-marklogo.c new file mode 100644 index 00000000000..b3efac4c2fa --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/slave/icons/cornepro-marklogo.c @@ -0,0 +1,48 @@ +#if defined(LV_LVGL_H_INCLUDE_SIMPLE) +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_MARKLOGO +#define LV_ATTRIBUTE_IMG_MARKLOGO +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_MARKLOGO uint8_t marklogo_map[] = { + 0x00, 0x00, 0x00, 0x09, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xd5, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xab, 0x68, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2d, 0x48, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0xd8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1a, 0x50, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x02, 0x12, 0xf0, + 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3d, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x07, 0x02, 0xf0, 0xf0, 0x1c, 0x00, 0x00, + 0x70, 0x1f, 0xc7, 0xf1, 0xf8, 0x7f, 0x00, 0x00, + 0xe0, 0x1b, 0xc7, 0xf3, 0xbc, 0xf7, 0x00, 0x00, + 0xe0, 0x38, 0xc6, 0x03, 0x9c, 0xc7, 0x00, 0x00, + 0xe0, 0x31, 0xce, 0x03, 0x19, 0xee, 0x00, 0x00, + 0xe0, 0x70, 0xce, 0x03, 0x19, 0xfe, 0x00, 0x00, + 0xe0, 0x71, 0xce, 0x07, 0x39, 0xe0, 0x00, 0x00, + 0xe2, 0x33, 0x8c, 0x07, 0x39, 0xc0, 0x00, 0x00, + 0x7e, 0x3f, 0x1c, 0x06, 0x30, 0xfe, 0x00, 0x00, + 0x3e, 0x1e, 0x0c, 0x06, 0x30, 0x7c, 0x00, 0x00, +}; + +const lv_img_dsc_t marklogo = { + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 61, + .header.h = 18, + .data_size = 152, + .data = marklogo_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/customlogo.c b/app/boards/arm/nrfmacro/epd_screen/slave/icons/customlogo.c new file mode 100644 index 00000000000..77640717994 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/slave/icons/customlogo.c @@ -0,0 +1,87 @@ +#include "lvgl.h" + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_CUSTOMLOGO +#define LV_ATTRIBUTE_IMG_CUSTOMLOGO +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_CUSTOMLOGO uint8_t customlogo_map[] = { + 0x00, 0x00, 0x00, 0x06, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xdb, /*Color of index 1*/ + + 0x1f, 0xdf, 0x1e, 0x7f, 0x00, 0x00, 0xfe, 0x00, 0x00, + 0x1f, 0x9f, 0x3f, 0x7f, 0x00, 0x07, 0xff, 0xc0, 0x00, + 0x06, 0x18, 0x30, 0x1c, 0x00, 0x1f, 0x43, 0xf0, 0x00, + 0x06, 0x1f, 0x3c, 0x0c, 0x00, 0x7c, 0x00, 0x7c, 0x00, + 0x06, 0x1f, 0x1f, 0x18, 0x00, 0xf0, 0x00, 0x1e, 0x00, + 0x06, 0x18, 0x03, 0x0c, 0x01, 0xc0, 0x00, 0x07, 0x00, + 0x06, 0x1d, 0x37, 0x18, 0x03, 0x80, 0x00, 0x03, 0x00, + 0x06, 0x1f, 0x3e, 0x0c, 0x03, 0x00, 0x00, 0x03, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x01, 0xc0, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x07, 0xc0, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x3c, 0x00, + 0x07, 0xff, 0xff, 0xf0, 0x1c, 0x00, 0x00, 0xf8, 0x00, + 0x3f, 0xff, 0xff, 0xfc, 0x18, 0x00, 0x01, 0xe0, 0x00, + 0x7d, 0x55, 0x55, 0x5e, 0x18, 0x00, 0x07, 0x80, 0x00, + 0x60, 0x00, 0x00, 0x06, 0x18, 0x00, 0x0f, 0x00, 0x00, + 0xe0, 0x00, 0x00, 0x07, 0x18, 0x00, 0x3f, 0x40, 0x00, + 0xc0, 0x00, 0x00, 0x03, 0x18, 0x00, 0x7f, 0xff, 0xa0, + 0xc0, 0x00, 0x00, 0x03, 0x18, 0x00, 0x01, 0x7f, 0xf0, + 0xc0, 0x00, 0x00, 0x03, 0x18, 0x00, 0x00, 0x01, 0x70, + 0xc0, 0x00, 0x00, 0x03, 0x18, 0x00, 0x00, 0x00, 0x60, + 0xc0, 0x00, 0x00, 0x03, 0x0c, 0x00, 0x00, 0x00, 0x70, + 0xc0, 0x00, 0x00, 0x03, 0x0c, 0x00, 0x00, 0x00, 0x60, + 0xc0, 0x00, 0x00, 0x03, 0x0e, 0x00, 0x00, 0x00, 0xe0, + 0xc0, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0x00, 0xc0, + 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xc0, + 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x80, + 0xc0, 0x03, 0x80, 0x03, 0x01, 0xc0, 0x01, 0xc7, 0x00, + 0xc0, 0x01, 0x80, 0x03, 0x01, 0xe0, 0x01, 0x8e, 0x00, + 0xc0, 0x01, 0xc0, 0x03, 0x00, 0x70, 0x03, 0xbc, 0x00, + 0xc0, 0x00, 0xe0, 0x03, 0x00, 0x3e, 0x07, 0x78, 0x00, + 0xc0, 0x00, 0x60, 0x03, 0x00, 0x1f, 0xff, 0xe0, 0x00, + 0xc0, 0x00, 0x70, 0x03, 0x00, 0x03, 0xff, 0x80, 0x00, + 0xc0, 0x00, 0x30, 0x03, 0x00, 0x00, 0x5c, 0x00, 0x00, + 0xc0, 0x00, 0x38, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, + 0xc0, 0x00, 0x1c, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, + 0xc0, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x70, 0x00, 0x00, + 0xc0, 0x00, 0x0e, 0x03, 0x00, 0x00, 0x60, 0x00, 0x00, + 0xe0, 0x00, 0x06, 0x07, 0x00, 0x00, 0xe0, 0x00, 0x00, + 0x70, 0x00, 0x07, 0x0e, 0x00, 0x01, 0xc0, 0x00, 0x00, + 0x3f, 0xff, 0xff, 0xfc, 0x00, 0x01, 0x80, 0x00, 0x00, + 0x1f, 0xff, 0xff, 0xf8, 0x00, 0x03, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0xe0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x01, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x03, 0x80, 0x00, 0x00, 0x00, + 0x1e, 0x78, 0xe6, 0x7b, 0x87, 0x00, 0xe3, 0x9f, 0x00, + 0x13, 0x4d, 0x32, 0x49, 0xc6, 0x00, 0xf3, 0x9f, 0x00, + 0x02, 0x08, 0x26, 0x1c, 0xce, 0x00, 0xf7, 0x98, 0x00, + 0x06, 0x38, 0xe2, 0x18, 0xec, 0x00, 0xf7, 0x9f, 0x00, + 0x04, 0x0c, 0x32, 0x20, 0x78, 0x00, 0xdd, 0x9f, 0x00, + 0x08, 0x0c, 0x30, 0x00, 0x78, 0x00, 0xdd, 0x98, 0x00, + 0x1b, 0x4d, 0x32, 0x20, 0x30, 0x00, 0xc9, 0x9d, 0x00, + 0x1f, 0x79, 0xe2, 0x20, 0x00, 0x00, 0xc1, 0x9f, 0x80, +}; + +const lv_img_dsc_t customlogo = { + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 68, + .header.h = 62, + .data_size = 566, + .data = customlogo_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/beer.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/beer.png new file mode 100644 index 00000000000..7b2376badc5 Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/beer.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/communism1.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/communism1.png new file mode 100644 index 00000000000..15d22c87eae Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/communism1.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/communism2.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/communism2.png new file mode 100644 index 00000000000..e6f80e5b749 Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/communism2.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/communism3.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/communism3.png new file mode 100644 index 00000000000..32bf84f5cf2 Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/communism3.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/cornepro-marklogo.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/cornepro-marklogo.png new file mode 100644 index 00000000000..a76d924900c Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/cornepro-marklogo.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/eye_of_horus2.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/eye_of_horus2.png new file mode 100644 index 00000000000..f755fc1a247 Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/eye_of_horus2.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/figure.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/figure.png new file mode 100644 index 00000000000..a7c91660ff8 Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/figure.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/finger.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/finger.png new file mode 100644 index 00000000000..9cb580b4219 Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/finger.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/girl1.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/girl1.png new file mode 100644 index 00000000000..cf74ddf00fc Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/girl1.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/horse.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/horse.png new file mode 100644 index 00000000000..334d6cfc9da Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/horse.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/karl_marx.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/karl_marx.png new file mode 100644 index 00000000000..8f419ab9202 Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/karl_marx.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/stdlogo.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/stdlogo.png new file mode 100644 index 00000000000..881749d7610 Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/stdlogo.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/test_64x64.svg b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/test_64x64.svg new file mode 100644 index 00000000000..bda5a54c608 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/test_64x64.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + TEST + ME + 233!? + + diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/testlogo_68x62.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/testlogo_68x62.png new file mode 100644 index 00000000000..3a116f76794 Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/testlogo_68x62.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/we_need_you.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/we_need_you.png new file mode 100644 index 00000000000..0a75f3d14d8 Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/we_need_you.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/wukong.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/wukong.png new file mode 100644 index 00000000000..22559aeaaa1 Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/wukong.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/wukong2.png b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/wukong2.png new file mode 100644 index 00000000000..091c46efea7 Binary files /dev/null and b/app/boards/arm/nrfmacro/epd_screen/slave/icons/pictures/wukong2.png differ diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/stdlogo.c b/app/boards/arm/nrfmacro/epd_screen/slave/icons/stdlogo.c new file mode 100644 index 00000000000..a04d632acdb --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/slave/icons/stdlogo.c @@ -0,0 +1,95 @@ +#include "lvgl.h" + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_STDLOGO +#define LV_ATTRIBUTE_IMG_STDLOGO +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_STDLOGO uint8_t stdlogo_map[] = { + 0x00, 0x00, 0x00, 0x04, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xef, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0xff, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xff, 0xea, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x0f, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x01, 0xfc, 0x00, 0x00, + 0x00, 0x01, 0xfe, 0x01, 0x7d, 0x00, 0x3f, 0x00, 0x00, + 0x00, 0x07, 0xf0, 0x1f, 0xff, 0xf0, 0x0f, 0xe0, 0x00, + 0x00, 0x3f, 0xc0, 0x7f, 0xff, 0xfe, 0x03, 0xfa, 0x20, + 0x15, 0xff, 0x03, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xe0, + 0x1f, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0x80, + 0x07, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x7f, 0xff, 0xfc, 0x7f, 0x00, 0x00, + 0x00, 0x0f, 0xf8, 0x3f, 0xff, 0xf8, 0x1f, 0xe0, 0x00, + 0x01, 0xff, 0xe0, 0x1f, 0xff, 0xf8, 0x07, 0xfe, 0x00, + 0x01, 0xff, 0xc0, 0x1f, 0xff, 0xf0, 0x01, 0xfc, 0x00, + 0x00, 0x7f, 0xe0, 0x0f, 0xff, 0xe0, 0x03, 0xf0, 0x00, + 0x00, 0x7b, 0xf8, 0x07, 0xff, 0xc0, 0x0f, 0xc0, 0x00, + 0x00, 0x00, 0xfe, 0x01, 0xff, 0x00, 0x3f, 0x80, 0x00, + 0x00, 0x00, 0x3f, 0x80, 0x00, 0x01, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x07, 0xf8, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xfc, 0x00, 0xbf, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xe0, 0x00, 0x00, + 0x00, 0x1f, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x3f, 0xf0, 0x00, 0x00, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0xff, 0xf8, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x00, + 0x01, 0xff, 0xfc, 0x00, 0x07, 0xef, 0xc0, 0x00, 0x00, + 0x01, 0xff, 0xfc, 0x00, 0x0f, 0xdf, 0xc0, 0x00, 0x00, + 0x03, 0xef, 0xfc, 0x00, 0x0f, 0x9f, 0xe0, 0x00, 0x00, + 0x03, 0xef, 0xfc, 0x00, 0x1f, 0x1f, 0xe0, 0x00, 0x00, + 0x03, 0xe7, 0xfc, 0x00, 0x3e, 0x1f, 0xf0, 0x00, 0x00, + 0x03, 0xc7, 0xf8, 0x00, 0x7c, 0x1f, 0xf8, 0x00, 0x00, + 0x03, 0xe3, 0xf8, 0x00, 0xf8, 0x1f, 0xfc, 0x00, 0x00, + 0x01, 0xe1, 0xe0, 0x01, 0xf8, 0x1f, 0xfc, 0x00, 0x00, + 0x01, 0xe0, 0x00, 0x07, 0xe0, 0x1f, 0xf8, 0x00, 0x00, + 0x01, 0xf0, 0x00, 0x0f, 0xe0, 0x1f, 0xf0, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x3f, 0x80, 0x1f, 0xe0, 0x00, 0x00, + 0x00, 0x7f, 0x00, 0xff, 0x00, 0x0f, 0xc0, 0x00, 0x00, + 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x0f, 0x80, 0x00, 0x00, + 0x00, 0x1f, 0xff, 0xfc, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xff, 0xc0, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t stdlogo = { + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 70, + .header.h = 70, + .data_size = 638, + .data = stdlogo_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/icons/sweepro-marklogo.c b/app/boards/arm/nrfmacro/epd_screen/slave/icons/sweepro-marklogo.c new file mode 100644 index 00000000000..711e91938ec --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/slave/icons/sweepro-marklogo.c @@ -0,0 +1,45 @@ +#include "lvgl.h" + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_MARKLOGO +#define LV_ATTRIBUTE_IMG_MARKLOGO +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_MARKLOGO uint8_t marklogo_map[] = { + 0x00, 0x00, 0x00, 0x06, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xc4, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x10, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x87, 0xbd, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0d, 0xef, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0d, 0x7b, 0x20, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x7a, 0x60, + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x06, 0x08, 0x5b, 0x40, + 0x70, 0x00, 0x00, 0x06, 0x03, 0x06, 0x18, 0x4b, 0xc0, + 0x60, 0x00, 0x00, 0x1e, 0x0f, 0x87, 0x00, 0x00, 0x00, + 0x3c, 0x18, 0x04, 0x3e, 0x1f, 0x0f, 0xc0, 0x00, 0x00, + 0x0f, 0x8b, 0x84, 0x78, 0x3e, 0x1c, 0x60, 0x00, 0x00, + 0x01, 0xdb, 0x0c, 0xc0, 0x30, 0x1c, 0x20, 0x00, 0x00, + 0x00, 0x4f, 0x98, 0x80, 0x60, 0x08, 0x60, 0x00, 0x00, + 0x55, 0xdf, 0x30, 0x80, 0xc0, 0x5f, 0xc0, 0x00, 0x00, + 0xff, 0x1d, 0xb0, 0xff, 0xff, 0xdf, 0x00, 0x00, 0x00, + 0x00, 0x09, 0xc0, 0x54, 0x2a, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t marklogo = { + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 67, + .header.h = 20, + .data_size = 188, + .data = marklogo_map, +}; diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/peripheral_status.c b/app/boards/arm/nrfmacro/epd_screen/slave/peripheral_status.c new file mode 100644 index 00000000000..43acfa38f41 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/slave/peripheral_status.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include "peripheral_status.h" +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct peripheral_status_state { + bool connected; +}; + +static struct peripheral_status_state get_state(const zmk_event_t *_eh) { + return (struct peripheral_status_state){.connected = zmk_split_bt_peripheral_is_connected()}; +} + +static void set_status_symbol(lv_obj_t *label, struct peripheral_status_state state) { + const char *text = + state.connected ? (LV_SYMBOL_WIFI " " LV_SYMBOL_OK) : (LV_SYMBOL_WIFI " " LV_SYMBOL_CLOSE); + + LOG_DBG("connected? %s", state.connected ? "true" : "false"); + lv_label_set_text(label, text); +} + +static void output_status_update_cb(struct peripheral_status_state state) { + struct zmk_widget_peripheral_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_status_symbol(widget->obj, state); } +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_peripheral_status, struct peripheral_status_state, + output_status_update_cb, get_state) +ZMK_SUBSCRIPTION(widget_peripheral_status, zmk_split_peripheral_status_changed); + +int zmk_widget_peripheral_status_init(struct zmk_widget_peripheral_status *widget, + lv_obj_t *parent) { + widget->obj = lv_label_create(parent, NULL); + + lv_obj_set_size(widget->obj, 40, 15); + + sys_slist_append(&widgets, &widget->node); + + widget_peripheral_status_init(); + return 0; +} + +lv_obj_t *zmk_widget_peripheral_status_obj(struct zmk_widget_peripheral_status *widget) { + return widget->obj; +} diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/peripheral_status.h b/app/boards/arm/nrfmacro/epd_screen/slave/peripheral_status.h new file mode 100644 index 00000000000..e3b41355eb8 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/slave/peripheral_status.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +struct zmk_widget_peripheral_status { + sys_snode_t node; + lv_obj_t *obj; +}; + +int zmk_widget_peripheral_status_init(struct zmk_widget_peripheral_status *widget, + lv_obj_t *parent); +lv_obj_t *zmk_widget_peripheral_status_obj(struct zmk_widget_peripheral_status *widget); \ No newline at end of file diff --git a/app/boards/arm/nrfmacro/epd_screen/slave/status_screen.c b/app/boards/arm/nrfmacro/epd_screen/slave/status_screen.c new file mode 100644 index 00000000000..e3dce0b9c14 --- /dev/null +++ b/app/boards/arm/nrfmacro/epd_screen/slave/status_screen.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "peripheral_status.h" +#include "battery_status.h" +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +LV_IMG_DECLARE(marklogo); +#if IS_ENABLED(CONFIG_NRFMACRO_SCREEN_STANDARD_LOGO) +LV_IMG_DECLARE(stdlogo); +#endif +#if IS_ENABLED(CONFIG_NRFMACRO_SCREEN_CUSTOM_LOGO) +LV_IMG_DECLARE(customlogo); +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_BATTERY_STATUS) +static struct zmk_widget_battery_status battery_status_widget; +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_PERIPHERAL_STATUS) +static struct zmk_widget_peripheral_status peripheral_status_widget; +#endif + +lv_obj_t *zmk_display_status_screen() { + lv_obj_t *screen; + + screen = lv_obj_create(NULL, NULL); + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_BATTERY_STATUS) + zmk_widget_battery_status_init(&battery_status_widget, screen); + lv_obj_align(zmk_widget_battery_status_obj(&battery_status_widget), NULL, LV_ALIGN_IN_TOP_RIGHT, + -CONFIG_NRFMACRO_SCREEN_RIGHT_MARGIN, CONFIG_NRFMACRO_SCREEN_TOP_MARGIN); +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_PERIPHERAL_STATUS) + zmk_widget_peripheral_status_init(&peripheral_status_widget, screen); + lv_obj_align(zmk_widget_peripheral_status_obj(&peripheral_status_widget), NULL, + LV_ALIGN_IN_TOP_LEFT, CONFIG_NRFMACRO_SCREEN_LEFT_MARGIN, CONFIG_NRFMACRO_SCREEN_TOP_MARGIN); +#endif + + // todo: + // 1. a product mark line (sweep-pro) +#if IS_ENABLED(CONFIG_NRFMACRO_SCREEN_MARK_LOGO) + lv_obj_t * marklogo_icon; + marklogo_icon = lv_img_create(screen, NULL); + lv_img_set_src(marklogo_icon, &marklogo); + lv_obj_align(marklogo_icon, NULL, LV_ALIGN_IN_BOTTOM_MID, CONFIG_NRFMACRO_SCREEN_LEFT_MARGIN, -CONFIG_NRFMACRO_SCREEN_BOTTOM_MARGIN); +#endif + // 2. a product logo +#if IS_ENABLED(CONFIG_NRFMACRO_SCREEN_STANDARD_LOGO) + lv_obj_t * stdlogo_icon; + stdlogo_icon = lv_img_create(screen, NULL); + lv_img_set_src(stdlogo_icon, &stdlogo); + lv_obj_align(stdlogo_icon, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, -28-CONFIG_NRFMACRO_SCREEN_BOTTOM_MARGIN); +#endif + // 3. configurable personal logo, which can replace the product logo +#if IS_ENABLED(CONFIG_NRFMACRO_SCREEN_CUSTOM_LOGO) + lv_obj_t * customlogo_icon; + customlogo_icon = lv_img_create(screen, NULL); + lv_img_set_src(customlogo_icon, &customlogo); + lv_obj_align(customlogo_icon, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, -28-CONFIG_NRFMACRO_SCREEN_BOTTOM_MARGIN); +#endif + + lv_refr_now(NULL); + + return screen; +} diff --git a/app/boards/arm/nrfmacro/nrfmacro.dts b/app/boards/arm/nrfmacro/nrfmacro.dts new file mode 100644 index 00000000000..ad2592054b3 --- /dev/null +++ b/app/boards/arm/nrfmacro/nrfmacro.dts @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include +#include "arduino_pro_micro_pins.dtsi" + +/ { + model = "nrfmacro"; + compatible = "ufan,nrfmacro"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + label = "Blue LED"; + }; + }; + + vcc_ctrl: ext-power { + compatible = "zmk,ext-power-generic"; + label = "EXT_POWER"; + control-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + label = "BATTERY"; + io-channels = <&adc 2>; + output-ohms = <2000000>; + full-ohms = <(2000000 + 820000)>; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + compatible = "nordic,nrf-twi"; + sda-pin = <15>; + scl-pin = <17>; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + tx-pin = <6>; + rx-pin = <8>; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + label = "CDC_ACM_0"; + }; +}; + + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + label = "softdevice"; + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + label = "code_partition"; + reg = <0x00026000 0x000c6000>; + }; + + /* + * The flash starting at 0x000ec000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@ec000 { + label = "storage"; + reg = <0x000ec000 0x00008000>; + }; + + boot_partition: partition@f4000 { + label = "adafruit_boot"; + reg = <0x000f4000 0x0000c000>; + }; + }; +}; + +&spi1 { + /* nrfmacro.dts */ + compatible = "nordic,nrf-spim"; + sck-pin = <22>; + mosi-pin = <7>; + cs-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>; + // not used, but required by spim binding; can be reuesd in the keymap for normal key press + miso-pin = <5>; + + /* shield.dtsi */ + status = "disabled"; + + // spi-device: gooddisplay GDEW0102T4 + epd: il0323@0 { + compatible = "gooddisplay,il0323"; + reg = <0>; + label = "DISPLAY"; + spi-max-frequency = <4000000>; + + height = <128>; + width = <80>; + reset-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + dc-gpios = <&gpio1 2 GPIO_ACTIVE_LOW>; + busy-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; + pwr = [03 00 26 26]; + cdi = <0xd2>; + tcon = <0x22>; + }; +}; + +&i2c1 { + compatible = "nordic,nrf-twi"; + sda-pin = <34>; + scl-pin = <32>; + status = "disabled"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + label = "DISPLAY"; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; + +nrfmacro_spi: &spi1 {}; +nrfmacro_i2c: &i2c1 {}; + +// &pro_micro_spi { +// status = "disabled"; +// sck-pin = <26>; +// mosi-pin = <12>; +// miso-pin = <7>; +// cs-gpios = <&gpio0 22 GPIO_ACTIVE_LOW>; + +// // trackpad: trackpad@0 { +// // compatible = "cirque,pinnacle"; +// // // status = "okay"; +// // reg = <0>; +// // label = "cirque trackpad"; +// // spi-max-frequency = <1000000>; +// // dr-gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>; +// // invert-x; +// // sleep; +// // /* no-taps; */ +// // }; + +// trackball: trackball@0 { +// compatible = "pixart,pmw33xx"; +// reg = <0>; +// label = "Pixart PMW3360"; +// cs-gpios = <&gpio0 22 GPIO_ACTIVE_LOW>; +// motswk-gpios = <&gpio1 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; +// spi-max-frequency = <2000000>; +// cpi = <400>; +// }; +// }; \ No newline at end of file diff --git a/app/boards/arm/nrfmacro/nrfmacro.yaml b/app/boards/arm/nrfmacro/nrfmacro.yaml new file mode 100644 index 00000000000..e1b59a48818 --- /dev/null +++ b/app/boards/arm/nrfmacro/nrfmacro.yaml @@ -0,0 +1,17 @@ +identifier: nrfmacro +name: nrfmacro +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog + - spi + - i2c diff --git a/app/boards/arm/nrfmacro/nrfmacro.zmk.yml b/app/boards/arm/nrfmacro/nrfmacro.zmk.yml new file mode 100644 index 00000000000..12494c8ff6d --- /dev/null +++ b/app/boards/arm/nrfmacro/nrfmacro.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: nrfmacro +name: nrfMacro (epaper verion) +type: board +arch: arm +outputs: + - usb + - ble +url: https://github.com/ufan/nrfmacro/ +exposes: [pro_micro] diff --git a/app/boards/arm/nrfmacro/nrfmacro_defconfig b/app/boards/arm/nrfmacro/nrfmacro_defconfig new file mode 100644 index 00000000000..2da8d77c47b --- /dev/null +++ b/app/boards/arm/nrfmacro/nrfmacro_defconfig @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_NRFMACRO=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable GPIO +CONFIG_GPIO=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_CLOCK_CONTROL_NRF=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y diff --git a/app/boards/arm/nrfmacro/trackball/CMakeLists.txt b/app/boards/arm/nrfmacro/trackball/CMakeLists.txt new file mode 100644 index 00000000000..d9449b5615c --- /dev/null +++ b/app/boards/arm/nrfmacro/trackball/CMakeLists.txt @@ -0,0 +1,9 @@ +zephyr_library() +zephyr_library_sources_ifdef(CONFIG_PMW33XX trackball.c) +zephyr_library_sources_ifdef(CONFIG_PMW3360 trackball_new.c) +zephyr_library_sources_ifdef(CONFIG_PAW3395 trackball_new.c) +zephyr_library_sources_ifdef(CONFIG_PMW3610 trackball_new.c) + +zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include) +zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/drivers/sensor) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) diff --git a/app/boards/arm/nrfmacro/trackball/trackball.c b/app/boards/arm/nrfmacro/trackball/trackball.c new file mode 100644 index 00000000000..6ab91478b2f --- /dev/null +++ b/app/boards/arm/nrfmacro/trackball/trackball.c @@ -0,0 +1,252 @@ +#define DT_DRV_COMPAT pixart_pmw33xx + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define SCROLL_DIV_FACTOR 5 +/* #define SCROLL_LAYER_INDEX 4 */ +#define SCROLL_LAYER_INDEX COND_CODE_0(DT_INST_NODE_HAS_PROP(0, scroll_layer), (255), \ + (DT_INST_PROP(0, scroll_layer))) + +#define CPI_DIVIDOR COND_CODE_0(DT_INST_NODE_HAS_PROP(0, cpi_dividor), (1), \ + (DT_INST_PROP(0, cpi_dividor))) + + +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ +// in us +static int64_t last_interrupt_time = 0; +static int64_t current_interrupt_time = 0; +static int64_t interrupt_interval = 0; +static int64_t handler_duration = 0; +static int64_t send_report_duration = 0; +static int64_t idle_interval = 0; +static int64_t time_buffer = 0; +/* #endif */ + +static int polling_count = 0; +static int max_poll_count = 0; +static int polling_interval = 0; +#define BLE_POLL_COUNT 20 +#define BLE_POLL_INTERVAL 15 // in ms +#define USB_POLL_COUNT 300 +#define USB_POLL_INTERVAL 1 // in ms + +// +static struct sensor_value dx, dy; + +const struct device *trackball = DEVICE_DT_GET(DT_DRV_INST(0)); + +LOG_MODULE_REGISTER(trackball, CONFIG_SENSOR_LOG_LEVEL); + + +/* update and send report */ +static int64_t trackball_update_handler(struct k_work *work) { +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + int64_t start_time = k_ticks_to_us_floor64(k_uptime_ticks()); +/* #endif */ + + // remaining scroll from last update + static int8_t scroll_ver_rem = 0, scroll_hor_rem = 0; + dx.val1 = dx.val1/CPI_DIVIDOR; + dy.val1 = dy.val1/CPI_DIVIDOR; + + // update report with latest position + zmk_hid_mouse_movement_set(0, 0); + zmk_hid_mouse_scroll_set(0, 0); + + const uint8_t layer = zmk_keymap_highest_layer_active(); + if (layer == SCROLL_LAYER_INDEX) { // lower + const int16_t total_hor = dx.val1 + scroll_hor_rem, total_ver = -(dy.val1 + scroll_ver_rem); + scroll_hor_rem = total_hor % SCROLL_DIV_FACTOR; + scroll_ver_rem = total_ver % SCROLL_DIV_FACTOR; + zmk_hid_mouse_scroll_update(total_hor / SCROLL_DIV_FACTOR, total_ver / SCROLL_DIV_FACTOR); + } else { + zmk_hid_mouse_movement_update(CLAMP(dx.val1, INT8_MIN, INT8_MAX), CLAMP(dy.val1, INT8_MIN, INT8_MAX)); + } + + // send the report to host + zmk_endpoints_send_mouse_report(); + +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + return start_time = k_ticks_to_us_floor64(k_uptime_ticks()) - start_time; +/* #else */ +/* return 0; */ +/* #endif */ +} + +// polling work +static void trackball_poll_handler(struct k_work *work) { +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + current_interrupt_time = k_ticks_to_us_floor64(k_uptime_ticks()); + interrupt_interval = current_interrupt_time - last_interrupt_time; + idle_interval = current_interrupt_time - time_buffer; +/* #endif */ + + + // fetch latest position from sensor + int ret = sensor_sample_fetch(trackball); + if (ret < 0) { + LOG_ERR("fetch: %d", ret); + return; + } + + // get the x, y delta + ret = sensor_channel_get(trackball, SENSOR_CHAN_POS_DX, &dx); + if (ret < 0) { + LOG_ERR("get dx: %d", ret); + return; + } + ret = sensor_channel_get(trackball, SENSOR_CHAN_POS_DY, &dy); + if (ret < 0) { + LOG_ERR("get dy: %d", ret); + return; + } + + if(dx.val1 != 0 || dy.val1 != 0) { + // process the updated position and send to host + /* k_work_submit_to_queue(zmk_mouse_work_q(), &trackball_update); */ +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + send_report_duration = trackball_update_handler(NULL); +/* #else */ +/* trackball_update_handler(NULL); */ +/* #endif */ + LOG_INF("Position updated: poll interval: %lld; send time: %lld ; new pos: %d %d",\ + interrupt_interval, send_report_duration, dx.val1, dy.val1); + } + +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + time_buffer = k_ticks_to_us_floor64(k_uptime_ticks()); + handler_duration = time_buffer - current_interrupt_time; + LOG_DBG("idle time: %lld ; handler time cost: %lld", \ + idle_interval, handler_duration); + + last_interrupt_time = current_interrupt_time; +} + +K_WORK_DEFINE(trackball_poll_work, &trackball_poll_handler); + +// polling timer +void trackball_timer_expiry(struct k_timer *timer); +void trackball_timer_stop(struct k_timer *timer); + +K_TIMER_DEFINE(trackball_timer, trackball_timer_expiry, trackball_timer_stop); + +// timer expiry function +void trackball_timer_expiry(struct k_timer *timer) { + // check whether reaching the polling count limit + if(polling_count < max_poll_count) { + // submit polling work to mouse work queue + k_work_submit_to_queue(zmk_mouse_work_q(), &trackball_poll_work); + + // update status + polling_count++; + } + else { + // stop timer + k_timer_stop(&trackball_timer); + } +} + +// timer stop function +void trackball_timer_stop(struct k_timer *timer) { + // reset status + polling_count = 0; + + // resume motion interrupt line + const struct pmw33xx_config *cfg = trackball->config; + if (gpio_pin_interrupt_configure(cfg->motswk_spec.port, cfg->motswk_spec.pin, GPIO_INT_LEVEL_ACTIVE)) { + LOG_WRN("Unable to set MOTSWK GPIO interrupt"); + } +} + + +// trigger handler +static void trackball_trigger_handler(const struct device *dev, const struct sensor_trigger *trig) { + struct pmw33xx_data *data = dev->data; + LOG_INF("I'm OLD trackball implementation"); + + // do not resume motion interrupt + data->resume_interrupt = false; + + // start the polling timer + k_timer_start(&trackball_timer, K_NO_WAIT, K_MSEC(polling_interval)); +} + +static int trackball_init() { + + struct sensor_trigger trigger = { + .type = SENSOR_TRIG_DATA_READY, + .chan = SENSOR_CHAN_ALL, + }; + printk("trackball"); + if (sensor_trigger_set(trackball, &trigger, trackball_trigger_handler) < 0) { + LOG_ERR("can't set trigger"); + return -EIO; + }; + + // init polling parameters + switch (zmk_endpoints_selected()) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ZMK_ENDPOINT_USB: { + max_poll_count = USB_POLL_COUNT; + polling_interval = USB_POLL_INTERVAL; + return 0; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB) */ + +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ZMK_ENDPOINT_BLE: { + max_poll_count = BLE_POLL_COUNT; + polling_interval = BLE_POLL_INTERVAL; + return 0; + } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ + default: + LOG_ERR("Unsupported endpoint"); + return -ENOTSUP; + } +} + +SYS_INIT(trackball_init, APPLICATION, CONFIG_SENSOR_INIT_PRIORITY); + +////////////// +int trackball_endpoint_listener(const zmk_event_t *eh) { + LOG_INF("endpoint changing..."); + + // update polling parameters + switch (zmk_endpoints_selected()) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ZMK_ENDPOINT_USB: { + max_poll_count = USB_POLL_COUNT; + polling_interval = USB_POLL_INTERVAL; + break; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB) */ + +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ZMK_ENDPOINT_BLE: { + max_poll_count = BLE_POLL_COUNT; + polling_interval = BLE_POLL_INTERVAL; + break; + } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ + default: + LOG_ERR("Unsupported endpoint"); + } + + return ZMK_EV_EVENT_BUBBLE; +} + +ZMK_LISTENER(trackball, trackball_endpoint_listener) +ZMK_SUBSCRIPTION(trackball, zmk_endpoint_selection_changed) diff --git a/app/boards/arm/nrfmacro/trackball/trackball_new.c b/app/boards/arm/nrfmacro/trackball/trackball_new.c new file mode 100644 index 00000000000..7c8004cbb6c --- /dev/null +++ b/app/boards/arm/nrfmacro/trackball/trackball_new.c @@ -0,0 +1,271 @@ +#ifdef CONFIG_PMW3360 +#define DT_DRV_COMPAT pixart_pmw3360 +#include +#elif defined(CONFIG_PAW3395) +#define DT_DRV_COMPAT pixart_paw3395 +#include +#elif defined(CONFIG_PMW3610) +#define DT_DRV_COMPAT pixart_pmw3610 +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + + +#define SCROLL_DIV_FACTOR 5 +/* #define SCROLL_LAYER_INDEX 4 */ +#define SCROLL_LAYER_INDEX COND_CODE_0(DT_INST_NODE_HAS_PROP(0, scroll_layer), (255), \ + (DT_INST_PROP(0, scroll_layer))) + + +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ +// in us +static int64_t last_interrupt_time = 0; +static int64_t current_interrupt_time = 0; +static int64_t interrupt_interval = 0; +static int64_t handler_duration = 0; +static int64_t send_report_duration = 0; +static int64_t idle_interval = 0; +static int64_t time_buffer = 0; +/* #endif */ + +static int polling_count = 0; +static int max_poll_count = 0; +static int polling_interval = 0; +#define BLE_POLL_COUNT 20 +#define BLE_POLL_INTERVAL 15 // in ms +#define USB_POLL_COUNT 300 +#define USB_POLL_INTERVAL 1 // in ms + + +LOG_MODULE_REGISTER(trackball, CONFIG_SENSOR_LOG_LEVEL); + +// polling work +static void trackball_poll_handler(struct k_work *work) { +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + current_interrupt_time = k_ticks_to_us_floor64(k_uptime_ticks()); + interrupt_interval = current_interrupt_time - last_interrupt_time; + idle_interval = current_interrupt_time - time_buffer; +/* #endif */ + + // get the device pointer + struct pixart_data *data = CONTAINER_OF(work, struct pixart_data, poll_work); + const struct device *dev = data->dev; + + // fetch dx and dy from sensor and save them into pixart_data structure + int ret = sensor_sample_fetch(dev); + if (ret < 0) { + LOG_ERR("fetch: %d", ret); + return; + } + + /* // get the x, y delta */ + /* ret = sensor_channel_get(trackball, SENSOR_CHAN_POS_DX, &dx); */ + /* if (ret < 0) { */ + /* LOG_ERR("get dx: %d", ret); */ + /* return; */ + /* } */ + /* ret = sensor_channel_get(trackball, SENSOR_CHAN_POS_DY, &dy); */ + /* if (ret < 0) { */ + /* LOG_ERR("get dy: %d", ret); */ + /* return; */ + /* } */ + + // remaining scroll from last update + static int16_t scroll_ver_rem = 0, scroll_hor_rem = 0; + static int64_t start_time = 0; + if(data->x != 0 || data->y != 0) { + // process the updated position and send to host + /* k_work_submit_to_queue(zmk_mouse_work_q(), &trackball_update); */ + /* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + start_time = k_ticks_to_us_floor64(k_uptime_ticks()); + /* #endif */ + + // update report with latest position + zmk_hid_mouse_movement_set(0, 0); + zmk_hid_mouse_scroll_set(0, 0); + + const uint8_t layer = zmk_keymap_highest_layer_active(); + if (layer == SCROLL_LAYER_INDEX) { // lower + const int16_t total_hor = data->x + scroll_hor_rem, total_ver = -(data->y + scroll_ver_rem); + scroll_hor_rem = total_hor % SCROLL_DIV_FACTOR; + scroll_ver_rem = total_ver % SCROLL_DIV_FACTOR; + zmk_hid_mouse_scroll_update(total_hor / SCROLL_DIV_FACTOR, total_ver / SCROLL_DIV_FACTOR); + } else { + zmk_hid_mouse_movement_update(CLAMP(data->x, INT8_MIN, INT8_MAX), CLAMP(data->y, INT8_MIN, INT8_MAX)); + } + + // send the report to host + zmk_endpoints_send_mouse_report(); + + send_report_duration = k_ticks_to_us_floor64(k_uptime_ticks()) - start_time; + LOG_INF("Position updated: poll interval: %lld; send time: %lld ; new pos: %d %d",\ + interrupt_interval, send_report_duration, data->x, data->y); + } + +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + time_buffer = k_ticks_to_us_floor64(k_uptime_ticks()); + handler_duration = time_buffer - current_interrupt_time; + LOG_DBG("idle time: %lld ; handler time cost: %lld", \ + idle_interval, handler_duration); + + last_interrupt_time = current_interrupt_time; +} + +// trigger handler +static void trackball_trigger_handler(const struct device *dev, const struct sensor_trigger *trig) { + LOG_INF("I'm new trackball implementation"); + + struct pixart_data *data = dev->data; + + // do not resume motion interrupt by passing-in null handler + struct sensor_trigger trigger = { + .type = SENSOR_TRIG_DATA_READY, + .chan = SENSOR_CHAN_ALL, + }; + if (sensor_trigger_set(dev, &trigger, NULL) < 0) { + LOG_ERR("can't stop motion interrupt line"); + }; + + // start the polling timer (the real work now is dispatched to a timer-based polling) + k_timer_start(&data->poll_timer, K_NO_WAIT, K_MSEC(polling_interval)); +} + +// timer expiry function +void trackball_timer_expiry(struct k_timer *timer) { + struct pixart_data *data = CONTAINER_OF(timer, struct pixart_data, poll_timer); + + // check whether reaching the polling count limit + if(polling_count < max_poll_count) { + // submit polling work to mouse work queue + k_work_submit_to_queue(zmk_mouse_work_q(), &data->poll_work); + + // update status + polling_count++; + } + else { + // stop timer + k_timer_stop(&data->poll_timer); + } +} + +// timer stop function +void trackball_timer_stop(struct k_timer *timer) { + struct pixart_data *data = CONTAINER_OF(timer, struct pixart_data, poll_timer); + const struct device *dev = data->dev; + + // reset polling count + polling_count = 0; + + // resume motion interrupt line by setting the handler to a real object + struct sensor_trigger trigger = { + .type = SENSOR_TRIG_DATA_READY, + .chan = SENSOR_CHAN_ALL, + }; + if (sensor_trigger_set(dev, &trigger, trackball_trigger_handler) < 0) { + LOG_ERR("can't resume motion interrupt line"); + }; +} + + +/* Setup the trigger handler at system powerup */ +// The device instance should be determined in this step. All other functions should only +// use the device poiter passed as an argument. +// In this applaication, the devcie instance 'trackball' is hard-coded as the first +// pixart_pmw3360 node in dts file and used implicitly here. +static int trackball_init() { + LOG_INF("Init trackball_new"); + + // get the sensor device instance + const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); + struct pixart_data *data = dev->data; + + // setup the timer and handler function of the polling work + k_timer_init(&data->poll_timer, trackball_timer_expiry, trackball_timer_stop); + k_work_init(&data->poll_work, trackball_poll_handler); + + // set up the trigger handler (i.e. the entry point to other code in this file) + struct sensor_trigger trigger = { + .type = SENSOR_TRIG_DATA_READY, + .chan = SENSOR_CHAN_ALL, + }; + + int err; + int count = 0; + do { + err = sensor_trigger_set(dev, &trigger, trackball_trigger_handler); + if (err == -EBUSY) { + count++; + k_sleep(K_MSEC(10)); + } + } while (err == -EBUSY && count < 50); + + if (err) { + LOG_ERR("Cannot enable trigger"); + return err; + } + + // init polling parameters based on current endpoint + switch (zmk_endpoints_selected()) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ZMK_ENDPOINT_USB: { + max_poll_count = USB_POLL_COUNT; + polling_interval = USB_POLL_INTERVAL; + return 0; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB) */ + +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ZMK_ENDPOINT_BLE: { + max_poll_count = BLE_POLL_COUNT; + polling_interval = BLE_POLL_INTERVAL; + return 0; + } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ + default: + LOG_ERR("Unsupported endpoint"); + return -ENOTSUP; + } +} + +SYS_INIT(trackball_init, APPLICATION, CONFIG_SENSOR_INIT_PRIORITY); + +/* the following code dynamically changes poll rate based on endpoint changing */ +// The code execution is driven by the zmk event system instead of zephyr interrupt routine +int trackball_endpoint_listener(const zmk_event_t *eh) { + LOG_INF("endpoint changing..."); + + // update polling parameters + switch (zmk_endpoints_selected()) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ZMK_ENDPOINT_USB: { + max_poll_count = USB_POLL_COUNT; + polling_interval = USB_POLL_INTERVAL; + break; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB) */ + +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ZMK_ENDPOINT_BLE: { + max_poll_count = BLE_POLL_COUNT; + polling_interval = BLE_POLL_INTERVAL; + break; + } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ + default: + LOG_ERR("Unsupported endpoint"); + } + + return ZMK_EV_EVENT_BUBBLE; +} + +ZMK_LISTENER(trackball, trackball_endpoint_listener) +ZMK_SUBSCRIPTION(trackball, zmk_endpoint_selection_changed) diff --git a/app/boards/arm/nrfmacro/trackpad/CMakeLists.txt b/app/boards/arm/nrfmacro/trackpad/CMakeLists.txt new file mode 100644 index 00000000000..6148e7d61ee --- /dev/null +++ b/app/boards/arm/nrfmacro/trackpad/CMakeLists.txt @@ -0,0 +1,4 @@ +zephyr_library() +zephyr_library_sources(trackpad.c) +zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) diff --git a/app/boards/arm/nrfmacro/trackpad/trackpad.c b/app/boards/arm/nrfmacro/trackpad/trackpad.c new file mode 100644 index 00000000000..b60280cbc00 --- /dev/null +++ b/app/boards/arm/nrfmacro/trackpad/trackpad.c @@ -0,0 +1,130 @@ +#define DT_DRV_COMPAT cirque_pinnacle + +#include +#include + +#include +#include +#include +#include + +#define SCROLL_DIV_FACTOR 5 +#define SCROLL_LAYER_INDEX COND_CODE_0(DT_INST_NODE_HAS_PROP(0, scroll_layer), (255), \ + (DT_INST_PROP(0, scroll_layer))) + + +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ +// in us +static int64_t last_interrupt_time = 0; +static int64_t current_interrupt_time = 0; +static int64_t interrupt_interval = 0; +static int64_t handler_duration = 0; +static int64_t send_report_duration = 0; +static int64_t idle_interval = 0; +static int64_t time_buffer = 0; +/* #endif */ + +static struct sensor_value dx, dy, btn; + +const struct device *trackpad = DEVICE_DT_GET(DT_DRV_INST(0)); + +LOG_MODULE_REGISTER(trackpad, CONFIG_SENSOR_LOG_LEVEL); + +/* update and send report */ +static int64_t trackpad_update_handler(struct k_work *work) { +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + int64_t start_time = k_ticks_to_us_floor64(k_uptime_ticks()); +/* #endif */ + + // remaining scroll from last update + static int8_t scroll_ver_rem = 0, scroll_hor_rem = 0; + uint8_t button; + static uint8_t last_button = 0; + static uint8_t last_pressed = 0; + + // update report with latest position + zmk_hid_mouse_movement_set(0, 0); + zmk_hid_mouse_scroll_set(0, 0); + + const uint8_t layer = zmk_keymap_highest_layer_active(); + if (layer == SCROLL_LAYER_INDEX) { // lower + const int16_t total_hor = dx.val1 + scroll_hor_rem, total_ver = -(dy.val1 + scroll_ver_rem); + scroll_hor_rem = total_hor % SCROLL_DIV_FACTOR; + scroll_ver_rem = total_ver % SCROLL_DIV_FACTOR; + zmk_hid_mouse_scroll_update(total_hor / SCROLL_DIV_FACTOR, total_ver / SCROLL_DIV_FACTOR); + button = RCLK; + } else { + zmk_hid_mouse_movement_update(CLAMP(dx.val1, INT8_MIN, INT8_MAX), CLAMP(dy.val1, INT8_MIN, INT8_MAX)); + button = LCLK; + } + + if (!last_pressed && btn.val1) { + zmk_hid_mouse_buttons_press(button); + last_button = button; + } else if (last_pressed && !btn.val1) { + zmk_hid_mouse_buttons_release(last_button); + } + // send the report to host + zmk_endpoints_send_mouse_report(); + last_pressed = btn.val1; + +/* #if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) */ + return start_time = k_ticks_to_us_floor64(k_uptime_ticks()) - start_time; +/* #else */ +/* return 0; */ +/* #endif */ +} + +static void handle_trackpad(const struct device *dev, const struct sensor_trigger *trig) { + current_interrupt_time = k_ticks_to_us_floor64(k_uptime_ticks()); + interrupt_interval = current_interrupt_time - last_interrupt_time; + idle_interval = current_interrupt_time - time_buffer; + + + int ret = sensor_sample_fetch(dev); + if (ret < 0) { + LOG_ERR("fetch: %d", ret); + return; + } + + ret = sensor_channel_get(dev, SENSOR_CHAN_POS_DX, &dx); + if (ret < 0) { + LOG_ERR("get dx: %d", ret); + return; + } + ret = sensor_channel_get(dev, SENSOR_CHAN_POS_DY, &dy); + if (ret < 0) { + LOG_ERR("get dy: %d", ret); + return; + } + ret = sensor_channel_get(dev, SENSOR_CHAN_PRESS, &btn); + if (ret < 0) { + LOG_ERR("get btn: %d", ret); + return; + } + + send_report_duration = trackpad_update_handler(NULL); + + time_buffer = k_ticks_to_us_floor64(k_uptime_ticks()); + handler_duration = time_buffer - current_interrupt_time; + + LOG_INF("interrupt interval (us): %lld ; idle: %lld ; handler time cost: %lld",\ + interrupt_interval, idle_interval, handler_duration); + LOG_INF("Send report time cost: %lld; Position: %d %d", send_report_duration, dx.val1, dy.val1); + last_interrupt_time = current_interrupt_time; +} + +static int trackpad_init() { + struct sensor_trigger trigger = { + .type = SENSOR_TRIG_DATA_READY, + .chan = SENSOR_CHAN_ALL, + }; + printk("trackpad"); + if (sensor_trigger_set(trackpad, &trigger, handle_trackpad) < 0) { + LOG_ERR("can't set trigger"); + return -EIO; + }; + return 0; +} + +SYS_INIT(trackpad_init, APPLICATION, CONFIG_ZMK_KSCAN_INIT_PRIORITY); diff --git a/app/boards/arm/nrfmacro/widgets/CMakeLists.txt b/app/boards/arm/nrfmacro/widgets/CMakeLists.txt new file mode 100644 index 00000000000..29c5e2b57cb --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/CMakeLists.txt @@ -0,0 +1,7 @@ +# +# Copyright (c) 2021 Darryl deHaan +# SPDX-License-Identifier: MIT +# + +# add_subdirectory_ifdef(CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM fonts/) +# add_subdirectory_ifdef(CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM icons/) diff --git a/app/boards/arm/nrfmacro/widgets/battery_status.c b/app/boards/arm/nrfmacro/widgets/battery_status.c new file mode 100644 index 00000000000..6e8a5282f07 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/battery_status.c @@ -0,0 +1,165 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include "battery_status.h" +#include +#include +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); +static lv_style_t label_style; + +LV_IMG_DECLARE(batt_100); +LV_IMG_DECLARE(batt_100_chg); +LV_IMG_DECLARE(batt_75); +LV_IMG_DECLARE(batt_75_chg); +LV_IMG_DECLARE(batt_50); +LV_IMG_DECLARE(batt_50_chg); +LV_IMG_DECLARE(batt_25); +LV_IMG_DECLARE(batt_25_chg); +LV_IMG_DECLARE(batt_5); +LV_IMG_DECLARE(batt_5_chg); +LV_IMG_DECLARE(batt_0); +LV_IMG_DECLARE(batt_0_chg); + +static bool style_initialized = false; + +void battery_status_init() { + + if (style_initialized) { + return; + } + + style_initialized = true; + lv_style_init(&label_style); + lv_style_set_text_font(&label_style, LV_STATE_DEFAULT, &lv_font_montserrat_26); + lv_style_set_text_letter_space(&label_style, LV_STATE_DEFAULT, 1); + lv_style_set_text_line_space(&label_style, LV_STATE_DEFAULT, 1); + lv_style_set_text_color(&label_style, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_style_set_bg_color(&label_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); + + //lv_obj_t * batt_full_chg_icon = lv_img_create(lv_scr_act(), NULL); + //lv_img_set_src(batt_full_chg_icon, &batt_full_chg); +} + +K_MUTEX_DEFINE(battery_status_mutex); + +struct { + uint8_t level; +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + bool usb_present; +#endif +} battery_status_state; + +void set_battery_symbol(lv_obj_t *icon) { + + k_mutex_lock(&battery_status_mutex, K_FOREVER); + + uint8_t level = battery_status_state.level; + +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + if (level > 95) { + if (battery_status_state.usb_present) { + lv_img_set_src(icon, &batt_100_chg); + }else{ + lv_img_set_src(icon, &batt_100); + } + } else if (level > 74) { + if (battery_status_state.usb_present) { + lv_img_set_src(icon, &batt_75_chg); + }else{ + lv_img_set_src(icon, &batt_75); + } + } else if (level > 49) { + if (battery_status_state.usb_present) { + lv_img_set_src(icon, &batt_50_chg); + }else{ + lv_img_set_src(icon, &batt_50); + } + } else if (level > 24) { + if (battery_status_state.usb_present) { + lv_img_set_src(icon, &batt_25_chg); + }else{ + lv_img_set_src(icon, &batt_25); + } + } else if (level > 5) { + if (battery_status_state.usb_present) { + lv_img_set_src(icon, &batt_5_chg); + }else{ + lv_img_set_src(icon, &batt_5); + } + } else { + if (battery_status_state.usb_present) { + lv_img_set_src(icon, &batt_0_chg); + }else{ + lv_img_set_src(icon, &batt_0); + } + } + //lv_label_set_text(label, text); + //lv_img_set_src(icon, ); + +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + + k_mutex_unlock(&battery_status_mutex); + +} + +int zmk_widget_battery_status_init(struct zmk_widget_battery_status *widget, lv_obj_t *parent) { + battery_status_init(); + //widget->obj = lv_label_create(parent, NULL); + widget->obj = lv_img_create(parent, NULL); + //widget->obj2 = lv_label_create(parent, NULL); + lv_obj_add_style(widget->obj, LV_LABEL_PART_MAIN, &label_style); + + //lv_obj_set_size(widget->obj, 40, 15); + set_battery_symbol(widget->obj); + + sys_slist_append(&widgets, &widget->node); + + return 0; +} + +lv_obj_t *zmk_widget_battery_status_obj(struct zmk_widget_battery_status *widget) { + return widget->obj; +} + +void battery_status_update_cb(struct k_work *work) { + struct zmk_widget_battery_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_battery_symbol(widget->obj); } +} + +K_WORK_DEFINE(battery_status_update_work, battery_status_update_cb); + +int battery_status_listener(const zmk_event_t *eh) { + k_mutex_lock(&battery_status_mutex, K_FOREVER); + + battery_status_state.level = bt_bas_get_battery_level(); + +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + battery_status_state.usb_present = zmk_usb_is_powered(); +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + + k_mutex_unlock(&battery_status_mutex); + + k_work_submit_to_queue(zmk_display_work_q(), &battery_status_update_work); + return ZMK_EV_EVENT_BUBBLE; +} + +ZMK_LISTENER(widget_battery_status, battery_status_listener) +ZMK_SUBSCRIPTION(widget_battery_status, zmk_battery_state_changed); +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) +ZMK_SUBSCRIPTION(widget_battery_status, zmk_usb_conn_state_changed); +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ diff --git a/app/boards/arm/nrfmacro/widgets/battery_status.h b/app/boards/arm/nrfmacro/widgets/battery_status.h new file mode 100644 index 00000000000..c2ad4bf4094 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/battery_status.h @@ -0,0 +1,20 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#pragma once + +#include + +#include + +struct zmk_widget_battery_status { + sys_snode_t node; + lv_obj_t *obj; +}; + +int zmk_widget_battery_status_init(struct zmk_widget_battery_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_battery_status_obj(struct zmk_widget_battery_status *widget); \ No newline at end of file diff --git a/app/boards/arm/nrfmacro/widgets/icons/CMakeLists.txt b/app/boards/arm/nrfmacro/widgets/icons/CMakeLists.txt new file mode 100644 index 00000000000..19af8ead415 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/CMakeLists.txt @@ -0,0 +1,4 @@ +# +# Copyright (c) 2021 Darryl deHaan +# SPDX-License-Identifier: MIT +# \ No newline at end of file diff --git a/app/boards/arm/nrfmacro/widgets/icons/USB_connected.c b/app/boards/arm/nrfmacro/widgets/icons/USB_connected.c new file mode 100644 index 00000000000..8cf0badc38a --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/USB_connected.c @@ -0,0 +1,63 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_USB_CONNECTED +#define LV_ATTRIBUTE_IMG_USB_CONNECTED +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_USB_CONNECTED uint8_t USB_connected_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0xff, 0xff, 0xc0, + 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0x00, 0xff, 0xff, 0xff, 0xc0, + 0x01, 0xff, 0xff, 0xff, 0x80, + 0x03, 0xff, 0xff, 0xff, 0xfe, + 0x07, 0xff, 0xff, 0xff, 0xff, + 0x07, 0x1e, 0x30, 0x38, 0x07, + 0x0f, 0x1c, 0x20, 0x38, 0x07, + 0x0f, 0x1c, 0x47, 0x10, 0xc3, + 0x3e, 0x1c, 0x43, 0xf1, 0xc7, + 0x7e, 0x3c, 0x60, 0x70, 0x0e, + 0x7e, 0x3c, 0x70, 0x30, 0x0e, + 0x7e, 0x38, 0xfc, 0x33, 0xc7, + 0xfe, 0x18, 0x8f, 0x23, 0x87, + 0x0e, 0x00, 0xc6, 0x20, 0x07, + 0x0f, 0x01, 0xe0, 0x60, 0x0e, + 0x0f, 0x87, 0xf0, 0xe0, 0x3e, + 0x07, 0xff, 0xff, 0xff, 0xfc, + 0x07, 0xff, 0xff, 0xff, 0xf0, + 0x03, 0xff, 0xff, 0xfe, 0x00, + 0x01, 0xff, 0xff, 0xfc, 0x00, + 0x00, 0x7f, 0xff, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t USB_connected = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 164, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = USB_connected_map, +}; diff --git a/app/boards/arm/nrfmacro/widgets/icons/batt_0.c b/app/boards/arm/nrfmacro/widgets/icons/batt_0.c new file mode 100644 index 00000000000..d061f1d87bf --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/batt_0.c @@ -0,0 +1,65 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_0 +#define LV_ATTRIBUTE_IMG_BATT_0 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_0 uint8_t batt_0_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x00, 0x00, + 0x7f, 0xfd, 0xff, 0x7f, 0xf8, + 0xff, 0xfd, 0xff, 0x7f, 0xfc, + 0xff, 0xfd, 0xff, 0x7f, 0xfc, + 0xff, 0xfc, 0xfe, 0x7f, 0xfc, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x0f, + 0xf0, 0x00, 0x7c, 0x00, 0x0f, + 0xf0, 0x00, 0x7c, 0x00, 0x0f, + 0xf0, 0x00, 0x7c, 0x00, 0x0f, + 0xf0, 0x00, 0x7c, 0x00, 0x3f, + 0xf0, 0x00, 0x7c, 0x00, 0x3f, + 0xf0, 0x00, 0x7c, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0x01, 0xff, 0xfc, + 0xff, 0xff, 0x01, 0xff, 0xfc, + 0xff, 0xfe, 0x7c, 0xff, 0xfc, + 0x7f, 0xfc, 0xfe, 0x7f, 0xf8, + 0x00, 0x01, 0xff, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_0 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_0_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/batt_0_chg.c b/app/boards/arm/nrfmacro/widgets/icons/batt_0_chg.c new file mode 100644 index 00000000000..e05e1524f09 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/batt_0_chg.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_0_CHG +#define LV_ATTRIBUTE_IMG_BATT_0_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_0_CHG uint8_t batt_0_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, + 0x00, 0x00, 0x03, 0x80, 0x00, + 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, + 0xff, 0xff, 0xdf, 0x7f, 0xfc, + 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf0, 0x01, 0xfe, 0x00, 0x3f, + 0xf0, 0x03, 0xfc, 0x00, 0x3f, + 0xf0, 0x07, 0xfc, 0x00, 0x0f, + 0xf0, 0x0f, 0xff, 0xe0, 0x0f, + 0xf0, 0x1f, 0xff, 0xc0, 0x0f, + 0xf0, 0x00, 0x7f, 0x80, 0x0f, + 0xf0, 0x00, 0x7f, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfc, 0x00, 0x3f, + 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, + 0xff, 0xfb, 0xef, 0xff, 0xfc, + 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_0_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_0_chg_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/batt_100.c b/app/boards/arm/nrfmacro/widgets/icons/batt_100.c new file mode 100644 index 00000000000..915472c3e2b --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/batt_100.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_100 +#define LV_ATTRIBUTE_IMG_BATT_100 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_100 uint8_t batt_100_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0xff, 0xff, 0xff, 0x3f, + 0xf3, 0xff, 0xff, 0xff, 0x3f, + 0xf3, 0xff, 0xff, 0xff, 0x0f, + 0xf3, 0xff, 0xff, 0xff, 0x0f, + 0xf3, 0xff, 0xff, 0xff, 0x0f, + 0xf3, 0xff, 0xff, 0xff, 0x0f, + 0xf3, 0xff, 0xff, 0xff, 0x3f, + 0xf3, 0xff, 0xff, 0xff, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_100 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_100_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/batt_100_chg.c b/app/boards/arm/nrfmacro/widgets/icons/batt_100_chg.c new file mode 100644 index 00000000000..9ad05d61c76 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/batt_100_chg.c @@ -0,0 +1,65 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_100_CHG +#define LV_ATTRIBUTE_IMG_BATT_100_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_100_CHG uint8_t batt_100_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, + 0x00, 0x00, 0x03, 0x80, 0x00, + 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, + 0xff, 0xff, 0xdf, 0x7f, 0xfc, + 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf3, 0xfd, 0xfe, 0xff, 0x3f, + 0xf3, 0xfb, 0xfd, 0xff, 0x3f, + 0xf3, 0xf7, 0xfc, 0x07, 0x0f, + 0xf3, 0xef, 0xff, 0xef, 0x0f, + 0xf3, 0xdf, 0xff, 0xdf, 0x0f, + 0xf3, 0x80, 0x7f, 0xbf, 0x0f, + 0xf3, 0xff, 0x7f, 0x7f, 0x3f, + 0xf3, 0xfe, 0xfe, 0xff, 0x3f, + 0xf0, 0x00, 0xfc, 0x00, 0x3f, + 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, + 0xff, 0xfb, 0xef, 0xff, 0xfc, + 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_100_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_100_chg_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/batt_25.c b/app/boards/arm/nrfmacro/widgets/icons/batt_25.c new file mode 100644 index 00000000000..1dba62c2f6c --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/batt_25.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_25 +#define LV_ATTRIBUTE_IMG_BATT_25 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_25 uint8_t batt_25_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0xfc, 0x00, 0x00, 0x3f, + 0xf3, 0xfc, 0x00, 0x00, 0x3f, + 0xf3, 0xfc, 0x00, 0x00, 0x0f, + 0xf3, 0xfc, 0x00, 0x00, 0x0f, + 0xf3, 0xfc, 0x00, 0x00, 0x0f, + 0xf3, 0xfc, 0x00, 0x00, 0x0f, + 0xf3, 0xfc, 0x00, 0x00, 0x3f, + 0xf3, 0xfc, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_25 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_25_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/batt_25_chg.c b/app/boards/arm/nrfmacro/widgets/icons/batt_25_chg.c new file mode 100644 index 00000000000..544e71db7c5 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/batt_25_chg.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_25_CHG +#define LV_ATTRIBUTE_IMG_BATT_25_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_25_CHG uint8_t batt_25_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, + 0x00, 0x00, 0x03, 0x80, 0x00, + 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, + 0xff, 0xff, 0xdf, 0x7f, 0xfc, + 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf3, 0xf9, 0xfe, 0x00, 0x3f, + 0xf3, 0xfb, 0xfc, 0x00, 0x3f, + 0xf3, 0xf7, 0xfc, 0x00, 0x0f, + 0xf3, 0xef, 0xff, 0xe0, 0x0f, + 0xf3, 0xdf, 0xff, 0xc0, 0x0f, + 0xf3, 0x80, 0x7f, 0x80, 0x0f, + 0xf3, 0xf8, 0x7f, 0x00, 0x3f, + 0xf3, 0xf8, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfc, 0x00, 0x3f, + 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, + 0xff, 0xfb, 0xef, 0xff, 0xfc, + 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_25_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_25_chg_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/batt_5.c b/app/boards/arm/nrfmacro/widgets/icons/batt_5.c new file mode 100644 index 00000000000..a8c5ded9289 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/batt_5.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_5 +#define LV_ATTRIBUTE_IMG_BATT_5 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_5 uint8_t batt_5_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0x00, 0x00, 0x00, 0x0f, + 0xf3, 0x00, 0x00, 0x00, 0x0f, + 0xf3, 0x00, 0x00, 0x00, 0x0f, + 0xf3, 0x00, 0x00, 0x00, 0x0f, + 0xf3, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_5 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_5_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/batt_50.c b/app/boards/arm/nrfmacro/widgets/icons/batt_50.c new file mode 100644 index 00000000000..3c93ae5bc71 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/batt_50.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_50 +#define LV_ATTRIBUTE_IMG_BATT_50 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_50 uint8_t batt_50_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0xff, 0xf0, 0x00, 0x3f, + 0xf3, 0xff, 0xf0, 0x00, 0x3f, + 0xf3, 0xff, 0xf0, 0x00, 0x0f, + 0xf3, 0xff, 0xf0, 0x00, 0x0f, + 0xf3, 0xff, 0xf0, 0x00, 0x0f, + 0xf3, 0xff, 0xf0, 0x00, 0x0f, + 0xf3, 0xff, 0xf0, 0x00, 0x3f, + 0xf3, 0xff, 0xf0, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_50 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_50_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/batt_50_chg.c b/app/boards/arm/nrfmacro/widgets/icons/batt_50_chg.c new file mode 100644 index 00000000000..b21b4e25df3 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/batt_50_chg.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_50_CHG +#define LV_ATTRIBUTE_IMG_BATT_50_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_50_CHG uint8_t batt_50_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, + 0x00, 0x00, 0x03, 0x80, 0x00, + 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, + 0xff, 0xff, 0xdf, 0x7f, 0xfc, + 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf3, 0xfd, 0xfe, 0x00, 0x3f, + 0xf3, 0xfb, 0xfc, 0x00, 0x3f, + 0xf3, 0xf7, 0xfc, 0x00, 0x0f, + 0xf3, 0xef, 0xff, 0xe0, 0x0f, + 0xf3, 0xdf, 0xff, 0xc0, 0x0f, + 0xf3, 0x80, 0x7f, 0x80, 0x0f, + 0xf3, 0xff, 0x7f, 0x00, 0x3f, + 0xf3, 0xfe, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfc, 0x00, 0x3f, + 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, + 0xff, 0xfb, 0xef, 0xff, 0xfc, + 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_50_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_50_chg_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/batt_5_chg.c b/app/boards/arm/nrfmacro/widgets/icons/batt_5_chg.c new file mode 100644 index 00000000000..da96fc4da1b --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/batt_5_chg.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_5_CHG +#define LV_ATTRIBUTE_IMG_BATT_5_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_5_CHG uint8_t batt_5_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, + 0x00, 0x00, 0x03, 0x80, 0x00, + 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, + 0xff, 0xff, 0xdf, 0x7f, 0xfc, + 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf3, 0x01, 0xfe, 0x00, 0x3f, + 0xf3, 0x03, 0xfc, 0x00, 0x3f, + 0xf3, 0x07, 0xfc, 0x00, 0x0f, + 0xf3, 0x0f, 0xff, 0xe0, 0x0f, + 0xf3, 0x1f, 0xff, 0xc0, 0x0f, + 0xf3, 0x00, 0x7f, 0x80, 0x0f, + 0xf3, 0x00, 0x7f, 0x00, 0x3f, + 0xf3, 0x00, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfc, 0x00, 0x3f, + 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, + 0xff, 0xfb, 0xef, 0xff, 0xfc, + 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_5_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_5_chg_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/batt_75.c b/app/boards/arm/nrfmacro/widgets/icons/batt_75.c new file mode 100644 index 00000000000..cbba208ef88 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/batt_75.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_75 +#define LV_ATTRIBUTE_IMG_BATT_75 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_75 uint8_t batt_75_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0xff, 0xff, 0xe0, 0x3f, + 0xf3, 0xff, 0xff, 0xe0, 0x3f, + 0xf3, 0xff, 0xff, 0xe0, 0x0f, + 0xf3, 0xff, 0xff, 0xe0, 0x0f, + 0xf3, 0xff, 0xff, 0xe0, 0x0f, + 0xf3, 0xff, 0xff, 0xe0, 0x0f, + 0xf3, 0xff, 0xff, 0xe0, 0x3f, + 0xf3, 0xff, 0xff, 0xe0, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_75 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_75_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/batt_75_chg.c b/app/boards/arm/nrfmacro/widgets/icons/batt_75_chg.c new file mode 100644 index 00000000000..b2c2298d3b2 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/batt_75_chg.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_75_CHG +#define LV_ATTRIBUTE_IMG_BATT_75_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_75_CHG uint8_t batt_75_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, + 0x00, 0x00, 0x03, 0x80, 0x00, + 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, + 0xff, 0xff, 0xdf, 0x7f, 0xfc, + 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf3, 0xfd, 0xfe, 0xe0, 0x3f, + 0xf3, 0xfb, 0xfd, 0xe0, 0x3f, + 0xf3, 0xf7, 0xfc, 0x00, 0x0f, + 0xf3, 0xef, 0xff, 0xe0, 0x0f, + 0xf3, 0xdf, 0xff, 0xc0, 0x0f, + 0xf3, 0x80, 0x7f, 0xa0, 0x0f, + 0xf3, 0xff, 0x7f, 0x60, 0x3f, + 0xf3, 0xfe, 0xfe, 0xe0, 0x3f, + 0xf0, 0x00, 0xfc, 0x00, 0x3f, + 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, + 0xff, 0xfb, 0xef, 0xff, 0xfc, + 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_75_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_75_chg_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising.c b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising.c new file mode 100644 index 00000000000..89809d1ffbf --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising.c @@ -0,0 +1,66 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING uint8_t bluetooth_advertising_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, + 0x00, 0x7f, 0x00, 0x00, + 0x20, 0x7f, 0x80, 0x00, + 0x70, 0x77, 0xc0, 0x00, + 0xf8, 0x73, 0xe0, 0xc0, + 0x7c, 0x71, 0xe0, 0xe0, + 0x3e, 0x73, 0xc0, 0x70, + 0x1f, 0x77, 0x86, 0x30, + 0x0f, 0xff, 0x07, 0x30, + 0x07, 0xfe, 0x07, 0x38, + 0x03, 0xfc, 0x23, 0x38, + 0x01, 0xf8, 0x63, 0x18, + 0x01, 0xf8, 0x63, 0x18, + 0x03, 0xfc, 0x23, 0x38, + 0x07, 0xfe, 0x07, 0x38, + 0x0f, 0xff, 0x07, 0x30, + 0x1f, 0x77, 0x86, 0x70, + 0x3e, 0x73, 0xc0, 0x70, + 0x7c, 0x71, 0xe0, 0xe0, + 0xf8, 0x73, 0xe0, 0xc0, + 0x70, 0x77, 0xc0, 0x00, + 0x20, 0x7f, 0x80, 0x00, + 0x00, 0x7f, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising = { + .header.always_zero = 0, + .header.w = 29, + .header.h = 35, + .data_size = 148, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_map, +}; diff --git a/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising_1.c b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising_1.c new file mode 100644 index 00000000000..9fdc8e55a47 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising_1.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_1 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_1 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_1 uint8_t bluetooth_advertising_1_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xc0, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xe0, + 0xf8, 0xf3, 0xc1, 0xc0, 0x7f, 0xff, 0xe0, + 0x7c, 0xf3, 0xe0, 0xc0, 0xff, 0xff, 0xf0, + 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0x8f, 0xf8, + 0x1f, 0xff, 0x84, 0x61, 0xfe, 0x0f, 0xf8, + 0x0f, 0xff, 0x0e, 0x71, 0xfe, 0x0f, 0xf8, + 0x07, 0xfe, 0x06, 0x31, 0xff, 0xcf, 0xfc, + 0x03, 0xfc, 0x27, 0x33, 0xff, 0xcf, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xff, 0xcf, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xff, 0xcf, 0xfc, + 0x03, 0xfc, 0x27, 0x33, 0xff, 0xcf, 0xfc, + 0x07, 0xfe, 0x06, 0x31, 0xff, 0xcf, 0xfc, + 0x0f, 0xff, 0x0e, 0x71, 0xff, 0xcf, 0xf8, + 0x1f, 0xff, 0x84, 0x61, 0xff, 0xcf, 0xf8, + 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0xcf, 0xf8, + 0x7c, 0xf3, 0xe1, 0xc0, 0xff, 0xff, 0xf0, + 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xe0, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xe0, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x80, + 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising_1 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_1_map, +}; diff --git a/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising_2.c b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising_2.c new file mode 100644 index 00000000000..a0c4345d99b --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising_2.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_2 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_2 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_2 uint8_t bluetooth_advertising_2_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfe, 0x00, 0x00, 0x03, 0xfc, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x60, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xc0, + 0xf0, 0xf7, 0xc0, 0x80, 0x7f, 0xff, 0xe0, + 0x78, 0xf3, 0xe1, 0xc0, 0x7f, 0xff, 0xf0, + 0x3c, 0xf3, 0xc0, 0xe0, 0xff, 0x0f, 0xf0, + 0x1e, 0xf7, 0x84, 0xe1, 0xfe, 0x07, 0xf8, + 0x0f, 0xff, 0x0e, 0x71, 0xfc, 0x63, 0xf8, + 0x07, 0xfe, 0x0e, 0x71, 0xff, 0xf3, 0xfc, + 0x03, 0xfc, 0x06, 0x33, 0xff, 0xe3, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xff, 0xe7, 0xfc, + 0x01, 0xf8, 0xe7, 0x33, 0xff, 0xc7, 0xfc, + 0x01, 0xfc, 0x67, 0x33, 0xff, 0x8f, 0xfc, + 0x03, 0xfe, 0x06, 0x33, 0xff, 0x1f, 0xfc, + 0x07, 0xff, 0x0e, 0x71, 0xfe, 0x3f, 0xfc, + 0x0f, 0xff, 0x8e, 0x61, 0xfc, 0x03, 0xf8, + 0x1e, 0xf7, 0xc0, 0xe1, 0xfc, 0x03, 0xf8, + 0x3c, 0xf3, 0xe0, 0xc0, 0xff, 0xff, 0xf0, + 0x78, 0xf3, 0xe1, 0xc0, 0x7f, 0xff, 0xf0, + 0xf0, 0xf7, 0xc0, 0x80, 0x7f, 0xff, 0xe0, + 0x60, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xc0, + 0x00, 0xff, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0xfe, 0x00, 0x00, 0x03, 0xfc, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising_2 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_2_map, +}; diff --git a/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising_3.c b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising_3.c new file mode 100644 index 00000000000..3e70f082868 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising_3.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_3 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_3 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_3 uint8_t bluetooth_advertising_3_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xc0, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xe0, + 0xf8, 0xf3, 0xc1, 0xc0, 0x7f, 0xff, 0xf0, + 0x7c, 0xf3, 0xe0, 0xc0, 0xff, 0x9f, 0xf0, + 0x3e, 0xf7, 0xc0, 0xe0, 0xfe, 0x07, 0xf8, + 0x1f, 0xff, 0x84, 0x61, 0xfe, 0x03, 0xf8, + 0x0f, 0xff, 0x0e, 0x71, 0xfe, 0xe3, 0xfc, + 0x07, 0xfe, 0x06, 0x31, 0xff, 0xe3, 0xfc, + 0x03, 0xfc, 0x27, 0x33, 0xff, 0x87, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xff, 0x87, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xff, 0x83, 0xfc, + 0x03, 0xfc, 0x27, 0x33, 0xff, 0xf3, 0xfc, + 0x07, 0xfe, 0x06, 0x31, 0xfe, 0xf3, 0xfc, + 0x0f, 0xff, 0x0e, 0x71, 0xfc, 0x63, 0xfc, + 0x1f, 0xff, 0x84, 0x61, 0xfe, 0x03, 0xf8, + 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0x0f, 0xf8, + 0x7c, 0xf3, 0xe1, 0xc0, 0xff, 0xff, 0xf0, + 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xf0, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xe0, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xc0, + 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising_3 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_3_map, +}; diff --git a/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising_4.c b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising_4.c new file mode 100644 index 00000000000..3e8441f7b37 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising_4.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_4 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_4 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_4 uint8_t bluetooth_advertising_4_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xc0, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xe0, + 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xe0, + 0x7c, 0xf3, 0xe0, 0xc0, 0xff, 0xff, 0xf0, + 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0xcf, 0xf8, + 0x1f, 0xff, 0x84, 0x61, 0xff, 0x8f, 0xf8, + 0x0f, 0xff, 0x0e, 0x71, 0xff, 0x0f, 0xf8, + 0x07, 0xfe, 0x06, 0x31, 0xff, 0x0f, 0xfc, + 0x03, 0xfc, 0x27, 0x31, 0xfe, 0x4f, 0xfc, + 0x01, 0xf8, 0x67, 0x31, 0xfc, 0x4f, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xfc, 0xcf, 0xfc, + 0x03, 0xfc, 0x27, 0x31, 0xf8, 0x07, 0xfc, + 0x07, 0xfe, 0x06, 0x31, 0xf8, 0x03, 0xfc, + 0x0f, 0xff, 0x0e, 0x71, 0xf8, 0x07, 0xf8, + 0x1f, 0xff, 0x84, 0x61, 0xff, 0xcf, 0xf8, + 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0xcf, 0xf8, + 0x7c, 0xf3, 0xe1, 0xc0, 0xff, 0xff, 0xf0, + 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xe0, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xc0, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x80, + 0x00, 0xfe, 0x00, 0x00, 0x07, 0xff, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xf8, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising_4 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_4_map, +}; diff --git a/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising_5.c b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising_5.c new file mode 100644 index 00000000000..3b24c9d81e8 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_advertising_5.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_5 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_5 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_5 uint8_t bluetooth_advertising_5_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x80, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xe0, + 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xe0, + 0x7c, 0xf3, 0xe0, 0xe0, 0xff, 0xff, 0xf0, + 0x3e, 0xf7, 0xc0, 0xe1, 0xfe, 0x07, 0xf8, + 0x1f, 0xff, 0x84, 0x61, 0xfe, 0x07, 0xf8, + 0x0f, 0xff, 0x0e, 0x71, 0xfc, 0x7f, 0xf8, + 0x07, 0xfe, 0x06, 0x33, 0xfc, 0x7f, 0xfc, + 0x03, 0xfc, 0x27, 0x33, 0xfc, 0x07, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xfc, 0x03, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xff, 0x63, 0xfc, + 0x03, 0xfc, 0x27, 0x33, 0xff, 0xf3, 0xfc, + 0x07, 0xfe, 0x06, 0x33, 0xfe, 0xf3, 0xfc, + 0x0f, 0xff, 0x0e, 0x71, 0xfc, 0x63, 0xf8, + 0x1f, 0xff, 0x84, 0x61, 0xfe, 0x07, 0xf8, + 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0x0f, 0xf8, + 0x7c, 0xf3, 0xe1, 0xc0, 0xff, 0xff, 0xf0, + 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xe0, + 0x70, 0xf7, 0x80, 0x00, 0x3f, 0xff, 0xc0, + 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x80, + 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x01, 0xf8, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising_5 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_5_map, +}; diff --git a/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_1.c b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_1.c new file mode 100644 index 00000000000..1cb545aa2b2 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_1.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_1 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_1 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_1 uint8_t bluetooth_connected_1_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0xc0, + 0x78, 0x77, 0xc0, 0x00, 0x3f, 0xff, 0xe0, + 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, + 0x3e, 0x71, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x1f, 0x73, 0xc0, 0x00, 0xff, 0x8f, 0xf8, + 0x0f, 0xff, 0x80, 0x01, 0xfe, 0x0f, 0xf8, + 0x87, 0xff, 0x08, 0x01, 0xfe, 0x0f, 0xf8, + 0xc3, 0xfe, 0x18, 0x01, 0xff, 0xcf, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xff, 0xcf, 0xfc, + 0xf0, 0xf8, 0x78, 0x03, 0xff, 0xcf, 0xfc, + 0xf0, 0xfc, 0x78, 0x03, 0xff, 0xcf, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xff, 0xcf, 0xfc, + 0xc3, 0xfe, 0x18, 0x01, 0xff, 0xcf, 0xfc, + 0x87, 0xff, 0x08, 0x01, 0xff, 0xcf, 0xf8, + 0x0f, 0xff, 0x80, 0x01, 0xff, 0xcf, 0xf8, + 0x1e, 0x73, 0xc0, 0x00, 0xff, 0xcf, 0xf8, + 0x3c, 0x71, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x78, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, + 0x78, 0x77, 0xc0, 0x00, 0x3f, 0xff, 0xe0, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_1 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_1_map, +}; diff --git a/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_2.c b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_2.c new file mode 100644 index 00000000000..c5775a61167 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_2.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_2 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_2 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_2 uint8_t bluetooth_connected_2_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x03, 0xfc, 0x00, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0xc0, + 0x78, 0x73, 0xc0, 0x00, 0x7f, 0xff, 0xe0, + 0x7c, 0x71, 0xe0, 0x00, 0x7f, 0xff, 0xf0, + 0x3e, 0x73, 0xe0, 0x00, 0xff, 0x0f, 0xf0, + 0x1f, 0x77, 0xc0, 0x01, 0xfe, 0x07, 0xf8, + 0x0f, 0xff, 0x80, 0x01, 0xfc, 0x63, 0xf8, + 0x87, 0xff, 0x08, 0x01, 0xff, 0xf3, 0xfc, + 0xc3, 0xfe, 0x18, 0x03, 0xff, 0xe3, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xff, 0xe7, 0xfc, + 0xf0, 0xf8, 0x78, 0x03, 0xff, 0xc7, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xff, 0x8f, 0xfc, + 0xc3, 0xfe, 0x18, 0x03, 0xff, 0x1f, 0xfc, + 0x87, 0xff, 0x08, 0x01, 0xfe, 0x3f, 0xfc, + 0x0f, 0xff, 0x80, 0x01, 0xfc, 0x03, 0xf8, + 0x1f, 0x77, 0xc0, 0x01, 0xfc, 0x03, 0xf8, + 0x3e, 0x73, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x7c, 0x71, 0xe0, 0x00, 0x7f, 0xff, 0xf0, + 0x78, 0x73, 0xc0, 0x00, 0x7f, 0xff, 0xe0, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0xc0, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x03, 0xfc, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_2 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_2_map, +}; diff --git a/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_3.c b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_3.c new file mode 100644 index 00000000000..111b9d320a9 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_3.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_3 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_3 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_3 uint8_t bluetooth_connected_3_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x03, 0xfc, 0x00, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0xc0, + 0x78, 0x77, 0xc0, 0x00, 0x7f, 0xff, 0xe0, + 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xf0, + 0x3e, 0x71, 0xe0, 0x00, 0xff, 0x9f, 0xf0, + 0x1f, 0x73, 0xc0, 0x01, 0xfe, 0x07, 0xf8, + 0x0f, 0xff, 0x80, 0x01, 0xfc, 0x03, 0xf8, + 0x87, 0xff, 0x08, 0x01, 0xfe, 0xe3, 0xfc, + 0xc3, 0xfe, 0x18, 0x03, 0xff, 0xe3, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xff, 0x87, 0xfc, + 0xf0, 0xf8, 0x78, 0x03, 0xff, 0x87, 0xfc, + 0xf0, 0xfc, 0x78, 0x03, 0xff, 0x83, 0xfc, + 0xe1, 0xfe, 0x38, 0x03, 0xff, 0xf3, 0xfc, + 0xc3, 0xff, 0x18, 0x03, 0xfe, 0xf3, 0xfc, + 0x87, 0xff, 0x88, 0x01, 0xfc, 0x63, 0xf8, + 0x0f, 0xf7, 0xc0, 0x01, 0xfe, 0x03, 0xf8, + 0x1f, 0x73, 0xe0, 0x01, 0xff, 0x0f, 0xf8, + 0x3e, 0x71, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, + 0x78, 0x77, 0xc0, 0x00, 0x3f, 0xff, 0xe0, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x01, 0xf8, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_3 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_3_map, +}; diff --git a/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_4.c b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_4.c new file mode 100644 index 00000000000..3b2db361515 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_4.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_4 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_4 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_4 uint8_t bluetooth_connected_4_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x01, 0xf8, 0x00, + 0x00, 0x7f, 0x00, 0x00, 0x07, 0xff, 0x00, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, + 0x78, 0x77, 0xc0, 0x00, 0x3f, 0xff, 0xe0, + 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, + 0x3e, 0x71, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x1f, 0x73, 0xc0, 0x00, 0xff, 0xcf, 0xf8, + 0x0f, 0xff, 0x80, 0x01, 0xff, 0x8f, 0xf8, + 0x87, 0xff, 0x08, 0x01, 0xff, 0x0f, 0xf8, + 0xc3, 0xfe, 0x18, 0x01, 0xff, 0x0f, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xfe, 0x4f, 0xfc, + 0xf0, 0xf8, 0x78, 0x03, 0xfc, 0x4f, 0xfc, + 0xf0, 0xfc, 0x78, 0x03, 0xfc, 0xcf, 0xfc, + 0xe1, 0xfe, 0x38, 0x03, 0xf8, 0xc7, 0xfc, + 0xc3, 0xff, 0x18, 0x01, 0xf8, 0x03, 0xfc, + 0x87, 0xff, 0x88, 0x01, 0xf8, 0x03, 0xf8, + 0x0f, 0xf7, 0xc0, 0x01, 0xff, 0xcf, 0xf8, + 0x1f, 0x73, 0xe0, 0x00, 0xff, 0xcf, 0xf8, + 0x3e, 0x71, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, + 0x78, 0x77, 0xc0, 0x00, 0x3f, 0xff, 0xe0, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x01, 0xf8, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_4 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_4_map, +}; diff --git a/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_5.c b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_5.c new file mode 100644 index 00000000000..bab117b89dc --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_5.c @@ -0,0 +1,64 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_5 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_5 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_5 uint8_t bluetooth_connected_5_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x01, 0xfc, 0x00, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, + 0x78, 0x77, 0xc0, 0x00, 0x3f, 0xff, 0xe0, + 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, + 0x3e, 0x71, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x1f, 0x73, 0xc0, 0x01, 0xfe, 0x07, 0xf8, + 0x0f, 0xff, 0x80, 0x01, 0xfe, 0x07, 0xf8, + 0x87, 0xff, 0x08, 0x01, 0xfc, 0x7f, 0xf8, + 0xc3, 0xfe, 0x18, 0x03, 0xfc, 0x7f, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xfc, 0x07, 0xfc, + 0xf0, 0xf8, 0x78, 0x03, 0xfc, 0x03, 0xfc, + 0xf0, 0xfc, 0x78, 0x03, 0xff, 0x63, 0xfc, + 0xe1, 0xfe, 0x38, 0x03, 0xff, 0xf3, 0xfc, + 0xc3, 0xff, 0x18, 0x03, 0xfe, 0xf3, 0xfc, + 0x87, 0xff, 0x88, 0x01, 0xfc, 0x63, 0xf8, + 0x0f, 0xf7, 0xc0, 0x01, 0xfe, 0x07, 0xf8, + 0x1e, 0x73, 0xc0, 0x00, 0xff, 0x0f, 0xf8, + 0x3c, 0x71, 0xe0, 0x00, 0xff, 0xff, 0xf0, + 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, + 0x78, 0x77, 0xc0, 0x00, 0x3f, 0xff, 0xc0, + 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, + 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x01, 0xf8, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_5 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_5_map, +}; diff --git a/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_right.c b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_right.c new file mode 100644 index 00000000000..1e637bdf29a --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_connected_right.c @@ -0,0 +1,69 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_RIGHT +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_RIGHT +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_RIGHT uint8_t bluetooth_connected_right_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3f, 0x00, 0x00, 0x03, 0xf8, 0x00, + 0x00, 0x3f, 0x80, 0x00, 0x0f, 0xfe, 0x00, + 0x10, 0x3f, 0xc0, 0x00, 0x3f, 0xff, 0x80, + 0x38, 0x3b, 0xe0, 0x00, 0x7f, 0xff, 0xc0, + 0x7c, 0x39, 0xf0, 0x00, 0xff, 0xff, 0xe0, + 0x3e, 0x38, 0xf0, 0x01, 0xff, 0xff, 0xf0, + 0x1f, 0x39, 0xe0, 0x01, 0xff, 0xfe, 0x30, + 0x0f, 0xbb, 0xc0, 0x03, 0xff, 0xfc, 0x38, + 0x87, 0xff, 0x84, 0x03, 0xff, 0xf8, 0x38, + 0xc3, 0xff, 0x0c, 0x07, 0xff, 0xf0, 0x3c, + 0xe1, 0xfe, 0x1c, 0x07, 0xcf, 0xe0, 0x7c, + 0xf0, 0xfc, 0x3c, 0x07, 0x87, 0xc0, 0xfc, + 0xf0, 0xfc, 0x3c, 0x07, 0x83, 0x81, 0xfc, + 0xe1, 0xfe, 0x1c, 0x07, 0x81, 0x03, 0xfc, + 0xc3, 0xff, 0x0c, 0x07, 0xc0, 0x07, 0xfc, + 0x87, 0xff, 0x84, 0x07, 0xe0, 0x0f, 0xfc, + 0x0f, 0xbb, 0xc0, 0x03, 0xf0, 0x1f, 0xf8, + 0x1f, 0x39, 0xe0, 0x03, 0xf8, 0x3f, 0xf8, + 0x3e, 0x38, 0xf0, 0x01, 0xfc, 0xff, 0xf0, + 0x7c, 0x39, 0xf0, 0x01, 0xff, 0xff, 0xf0, + 0x38, 0x3b, 0xe0, 0x00, 0xff, 0xff, 0xe0, + 0x10, 0x3f, 0xc0, 0x00, 0x7f, 0xff, 0xc0, + 0x00, 0x3f, 0x80, 0x00, 0x3f, 0xff, 0x80, + 0x00, 0x3f, 0x00, 0x00, 0x0f, 0xfe, 0x00, + 0x00, 0x3e, 0x00, 0x00, 0x03, 0xf8, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_right = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 253, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_right_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/bluetooth_disconnected_right.c b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_disconnected_right.c new file mode 100644 index 00000000000..027856e2cd6 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/bluetooth_disconnected_right.c @@ -0,0 +1,68 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_DISCONNECTED_RIGHT +#define LV_ATTRIBUTE_IMG_BLUETOOTH_DISCONNECTED_RIGHT +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BLUETOOTH_DISCONNECTED_RIGHT uint8_t bluetooth_disconnected_right_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3f, 0x00, 0x00, 0x03, 0xf8, 0x00, + 0x00, 0x3f, 0x80, 0x00, 0x0f, 0xfe, 0x00, + 0x10, 0x3f, 0xc0, 0x00, 0x3f, 0xff, 0x80, + 0x38, 0x3b, 0xe0, 0x00, 0x7f, 0xff, 0xc0, + 0x7c, 0x39, 0xf0, 0x00, 0xff, 0xff, 0xe0, + 0x3e, 0x38, 0xf0, 0x01, 0xff, 0xff, 0xf0, + 0x1f, 0x39, 0xe0, 0x01, 0xe3, 0xf8, 0xf0, + 0x0f, 0xbb, 0xc0, 0x03, 0xe1, 0xf0, 0xf8, + 0x07, 0xff, 0x80, 0x03, 0xe0, 0xe0, 0xf8, + 0x03, 0xff, 0x00, 0x07, 0xf0, 0x01, 0xfc, + 0x01, 0xfe, 0x00, 0x07, 0xf8, 0x03, 0xfc, + 0x00, 0xfc, 0x00, 0x07, 0xfc, 0x07, 0xfc, + 0x00, 0xfc, 0x00, 0x07, 0xfc, 0x07, 0xfc, + 0x01, 0xfe, 0x00, 0x07, 0xfc, 0x07, 0xfc, + 0x03, 0xff, 0x00, 0x07, 0xf8, 0x03, 0xfc, + 0x07, 0xff, 0x80, 0x07, 0xf0, 0x01, 0xfc, + 0x0f, 0xbb, 0xc0, 0x03, 0xe0, 0xe0, 0xf8, + 0x1f, 0x39, 0xe0, 0x03, 0xe1, 0xf0, 0xf8, + 0x3e, 0x38, 0xf0, 0x01, 0xe3, 0xf8, 0xf0, + 0x7c, 0x39, 0xf0, 0x01, 0xff, 0xff, 0xf0, + 0x38, 0x3b, 0xe0, 0x00, 0xff, 0xff, 0xe0, + 0x10, 0x3f, 0xc0, 0x00, 0x7f, 0xff, 0xc0, + 0x00, 0x3f, 0x80, 0x00, 0x3f, 0xff, 0x80, + 0x00, 0x3f, 0x00, 0x00, 0x0f, 0xfe, 0x00, + 0x00, 0x3e, 0x00, 0x00, 0x03, 0xf8, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_disconnected_right = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 253, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_disconnected_right_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/layers.c b/app/boards/arm/nrfmacro/widgets/icons/layers.c new file mode 100644 index 00000000000..945b5cc9946 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/layers.c @@ -0,0 +1,68 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_LAYERS +#define LV_ATTRIBUTE_IMG_LAYERS +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_LAYERS uint8_t layers_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x00, 0x00, + 0x00, 0x07, 0xfc, 0x00, 0x00, + 0x00, 0x1f, 0xff, 0x00, 0x00, + 0x00, 0x7f, 0xff, 0xc0, 0x00, + 0x01, 0xff, 0xff, 0xf0, 0x00, + 0x07, 0xff, 0xff, 0xfc, 0x00, + 0x1f, 0xff, 0xff, 0xff, 0x00, + 0x3f, 0xff, 0xff, 0xff, 0x80, + 0x1f, 0xff, 0xff, 0xff, 0x00, + 0x0f, 0xff, 0xff, 0xfe, 0x00, + 0x01, 0xff, 0xff, 0xf0, 0x00, + 0x00, 0xff, 0xff, 0xe0, 0x00, + 0x07, 0x9f, 0xff, 0x3c, 0x00, + 0x1e, 0x07, 0xfc, 0x0f, 0x00, + 0x38, 0x01, 0xe0, 0x03, 0x80, + 0x30, 0x00, 0x00, 0x01, 0x80, + 0x38, 0x00, 0x00, 0x03, 0x80, + 0x0e, 0x00, 0x00, 0x0e, 0x00, + 0x03, 0xc0, 0x00, 0x78, 0x00, + 0x01, 0xf0, 0x01, 0xf0, 0x00, + 0x07, 0xfc, 0x07, 0xfc, 0x00, + 0x1f, 0xff, 0x1f, 0xff, 0x00, + 0x3f, 0xff, 0xff, 0xff, 0x80, + 0x3f, 0xff, 0xff, 0xff, 0x80, + 0x1f, 0xff, 0xff, 0xff, 0x00, + 0x07, 0xff, 0xff, 0xfc, 0x00, + 0x00, 0xff, 0xff, 0xf0, 0x00, + 0x00, 0x3f, 0xff, 0x80, 0x00, + 0x00, 0x0f, 0xfe, 0x00, 0x00, + 0x00, 0x03, 0xf8, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t layers = { + .header.always_zero = 0, + .header.w = 35, + .header.h = 35, + .data_size = 183, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = layers_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/layers2.c b/app/boards/arm/nrfmacro/widgets/icons/layers2.c new file mode 100644 index 00000000000..7a880557715 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/layers2.c @@ -0,0 +1,45 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_LAYERS +#define LV_ATTRIBUTE_IMG_LAYERS +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_LAYERS2 uint8_t layers_map[] = { + 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x30, 0x0f, 0x18, 0xdf, 0xdf, 0xc0, 0x04, 0x00, + 0x00, 0x80, 0x30, 0x19, 0x98, 0xd8, 0x18, 0xe0, 0x0e, 0x00, + 0x00, 0x80, 0x30, 0x30, 0xd8, 0xd8, 0x18, 0xe0, 0x1f, 0x00, + 0x00, 0x80, 0x30, 0x30, 0xcf, 0x9f, 0xd9, 0xc0, 0x04, 0x00, + 0x00, 0x80, 0x30, 0x3f, 0xc7, 0x18, 0x1f, 0x80, 0x04, 0x00, + 0x03, 0xe0, 0x30, 0x39, 0xc6, 0x18, 0x1b, 0x80, 0x04, 0x00, + 0x01, 0xc0, 0x3f, 0xb0, 0xc6, 0x1f, 0xd9, 0xc0, 0x04, 0x00, + 0x00, 0x80, 0x3f, 0xb0, 0xc6, 0x1f, 0xd8, 0xe0, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t layers = { + .header.always_zero = 0, + .header.w = 78, + .header.h = 12, + .data_size = 128, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = layers_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/icons/zenlogo.c b/app/boards/arm/nrfmacro/widgets/icons/zenlogo.c new file mode 100644 index 00000000000..93eefd482d4 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/icons/zenlogo.c @@ -0,0 +1,71 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include + + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_ZENLOGO +#define LV_ATTRIBUTE_IMG_ZENLOGO +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_ZENLOGO uint8_t zenlogo_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x03, 0xe3, 0xe3, 0x9e, 0x3e, 0x02, 0x72, 0xe0, 0x00, + 0x00, 0x06, 0x36, 0x36, 0x33, 0x63, 0x02, 0x8b, 0x10, 0x00, + 0x00, 0x04, 0x14, 0x14, 0x21, 0x41, 0x02, 0x82, 0x10, 0x00, + 0x00, 0x04, 0x04, 0x14, 0x21, 0x7f, 0x7a, 0x72, 0x10, 0x00, + 0x00, 0x04, 0x04, 0x14, 0x21, 0x40, 0x02, 0x0a, 0x10, 0x00, + 0x00, 0x04, 0x14, 0x14, 0x21, 0x41, 0x02, 0x0a, 0x10, 0x00, + 0x00, 0x06, 0x36, 0x34, 0x21, 0x63, 0x02, 0x8a, 0x10, 0x00, + 0x00, 0x03, 0xe3, 0xe4, 0x21, 0x3e, 0x02, 0x72, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x03, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x07, 0xe0, + 0x00, 0x00, 0x00, 0xff, 0xf1, 0xf8, 0x00, 0x60, 0x0f, 0xc0, + 0x00, 0x00, 0x0f, 0xff, 0xfb, 0xff, 0xe0, 0xf8, 0x1f, 0x80, + 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xfc, 0x1f, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xfc, 0x1f, 0x00, + 0x7f, 0xc0, 0x1f, 0xff, 0xff, 0xe0, 0x01, 0xfc, 0x3e, 0x00, + 0x40, 0x1f, 0xff, 0xe0, 0xff, 0xc0, 0x07, 0xfc, 0xfc, 0x00, + 0xdf, 0xff, 0x80, 0x01, 0xff, 0xc0, 0x0f, 0xdc, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x0f, 0xff, 0x8f, 0x1f, 0x9f, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x1f, 0xef, 0xff, 0x1f, 0x9f, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0x8f, 0xff, 0x3f, 0x1f, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x1f, 0xfe, 0x3f, 0x0f, 0xf0, 0x00, + 0x00, 0x00, 0x03, 0xf8, 0x1f, 0x80, 0x7e, 0x0f, 0xe0, 0x00, + 0x00, 0x00, 0x07, 0xe0, 0x3e, 0x00, 0x7e, 0x0f, 0xe0, 0x00, + 0x00, 0x00, 0x0f, 0xc0, 0x3c, 0x00, 0x7e, 0x0f, 0xc0, 0x00, + 0x00, 0x00, 0x1f, 0xf8, 0x3c, 0x00, 0x78, 0x0f, 0xc0, 0x00, + 0x00, 0x00, 0x1f, 0xff, 0xbc, 0x00, 0x78, 0x0f, 0xc0, 0x00, + 0x00, 0x00, 0x1f, 0xff, 0xfc, 0x00, 0xf8, 0x0f, 0xc0, 0x00, + 0x00, 0x00, 0x1f, 0xff, 0xfc, 0x0f, 0xf0, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t zenlogo = { + .header.always_zero = 0, + .header.w = 80, + .header.h = 38, + .data_size = 388, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = zenlogo_map, +}; + diff --git a/app/boards/arm/nrfmacro/widgets/layer_status.c b/app/boards/arm/nrfmacro/widgets/layer_status.c new file mode 100644 index 00000000000..92022629a12 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/layer_status.c @@ -0,0 +1,102 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); +#include +#include "layer_status.h" +#include +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); +static lv_style_t label_style; + +static bool style_initialized = false; + +K_MUTEX_DEFINE(layer_status_mutex); + +struct { + uint8_t index; + const char *label; +} layer_status_state; + +void layer_status_init() { + if (style_initialized) { + return; + } + style_initialized = true; + lv_style_init(&label_style); + lv_style_set_text_color(&label_style, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_style_set_text_font(&label_style, LV_STATE_DEFAULT, &lv_font_montserrat_16); + lv_style_set_text_letter_space(&label_style, LV_STATE_DEFAULT, 1); + lv_style_set_text_line_space(&label_style, LV_STATE_DEFAULT, 1); + +} + +void set_layer_symbol(lv_obj_t *label) { + + k_mutex_lock(&layer_status_mutex, K_FOREVER); + const char *layer_label = layer_status_state.label; + uint8_t active_layer_index = layer_status_state.index; + k_mutex_unlock(&layer_status_mutex); + + //LOG_DBG("Layer Label: %s", layer_label); + + if (layer_label == NULL) { + char text[6] = {}; + + sprintf(text, " %i", active_layer_index); + + lv_label_set_text(label, text); + } else { + lv_label_set_text(label, layer_label); + } +} + +static void update_state() { + k_mutex_lock(&layer_status_mutex, K_FOREVER); + layer_status_state.index = zmk_keymap_highest_layer_active(); + layer_status_state.label = zmk_keymap_layer_label(layer_status_state.index); + LOG_DBG("Layer changed to %i", layer_status_state.index); + + k_mutex_unlock(&layer_status_mutex); +} + +int zmk_widget_layer_status_init(struct zmk_widget_layer_status *widget, lv_obj_t *parent) { + layer_status_init(); + update_state(); + widget->obj = lv_label_create(parent, NULL); + lv_obj_add_style(widget->obj, LV_LABEL_PART_MAIN, &label_style); + set_layer_symbol(widget->obj); + sys_slist_append(&widgets, &widget->node); + + return 0; +} + +lv_obj_t *zmk_widget_layer_status_obj(struct zmk_widget_layer_status *widget) { + return widget->obj; +} + +void layer_status_update_cb(struct k_work *work) { + struct zmk_widget_layer_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_layer_symbol(widget->obj); } +} + +K_WORK_DEFINE(layer_status_update_work, layer_status_update_cb); + +int layer_status_listener(const zmk_event_t *eh) { + update_state();; + + k_work_submit_to_queue(zmk_display_work_q(), &layer_status_update_work); + return 0; +} + +ZMK_LISTENER(widget_layer_status, layer_status_listener) +ZMK_SUBSCRIPTION(widget_layer_status, zmk_layer_state_changed); \ No newline at end of file diff --git a/app/boards/arm/nrfmacro/widgets/layer_status.h b/app/boards/arm/nrfmacro/widgets/layer_status.h new file mode 100644 index 00000000000..2616ad225d0 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/layer_status.h @@ -0,0 +1,20 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#pragma once + +#include +#include + +struct zmk_widget_layer_status { + sys_snode_t node; + lv_obj_t *obj; + //lv_obj_t *obj2; +}; + +int zmk_widget_layer_status_init(struct zmk_widget_layer_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_layer_status_obj(struct zmk_widget_layer_status *widget); \ No newline at end of file diff --git a/app/boards/arm/nrfmacro/widgets/output_status.c b/app/boards/arm/nrfmacro/widgets/output_status.c new file mode 100644 index 00000000000..cbd83e3110d --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/output_status.c @@ -0,0 +1,190 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include "output_status.h" +#include +#include +#include +#include +#include +#include +#include + +LV_IMG_DECLARE(bluetooth_advertising); +LV_IMG_DECLARE(bluetooth_connected_right); +LV_IMG_DECLARE(bluetooth_disconnected_right); +LV_IMG_DECLARE(bluetooth_connected_1); +LV_IMG_DECLARE(bluetooth_connected_2); +LV_IMG_DECLARE(bluetooth_connected_3); +LV_IMG_DECLARE(bluetooth_connected_4); +LV_IMG_DECLARE(bluetooth_connected_5); +LV_IMG_DECLARE(bluetooth_advertising_1); +LV_IMG_DECLARE(bluetooth_advertising_2); +LV_IMG_DECLARE(bluetooth_advertising_3); +LV_IMG_DECLARE(bluetooth_advertising_4); +LV_IMG_DECLARE(bluetooth_advertising_5); +LV_IMG_DECLARE(USB_connected); + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); +static lv_style_t label_style; + +static bool style_initialized = false; + +K_MUTEX_DEFINE(output_status_mutex); + +struct { + enum zmk_endpoint selected_endpoint; + bool active_profile_connected; + bool active_profile_bonded; + uint8_t active_profile_index; +} output_status_state; + +void output_status_init() { + if (style_initialized) { + return; + } + + style_initialized = true; + lv_style_init(&label_style); + lv_style_set_text_color(&label_style, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_style_set_text_font(&label_style, LV_STATE_DEFAULT, &lv_font_montserrat_26); + lv_style_set_text_letter_space(&label_style, LV_STATE_DEFAULT, 1); + lv_style_set_text_line_space(&label_style, LV_STATE_DEFAULT, 1); +} + +void set_status_symbol(lv_obj_t *icon) { + + k_mutex_lock(&output_status_mutex, K_FOREVER); + enum zmk_endpoint selected_endpoint = output_status_state.selected_endpoint; + bool active_profile_connected = output_status_state.active_profile_connected; + bool active_profie_bonded = output_status_state.active_profile_bonded; + uint8_t active_profile_index = output_status_state.active_profile_index; + k_mutex_unlock(&output_status_mutex); + + switch (selected_endpoint) { + case ZMK_ENDPOINT_USB: + lv_img_set_src(icon, &USB_connected); + break; + case ZMK_ENDPOINT_BLE: + if (active_profie_bonded) { + if (active_profile_connected) { + //sprintf(text, LV_SYMBOL_BLUETOOTH "%i " LV_SYMBOL_OK, active_profile_index); + switch (active_profile_index) { + case 0: +#if IS_ENABLED(CONFIG_NRFMACRO_SHIELD_SLAVE) + lv_img_set_src(icon, &bluetooth_connected_right); +#else + lv_img_set_src(icon, &bluetooth_connected_1); +#endif + break; + case 1: + lv_img_set_src(icon, &bluetooth_connected_2); + break; + case 2: + lv_img_set_src(icon, &bluetooth_connected_3); + break; + case 3: + lv_img_set_src(icon, &bluetooth_connected_4); + break; + case 4: + lv_img_set_src(icon, &bluetooth_connected_5); + break; + } + } else { + //sprintf(text, LV_SYMBOL_BLUETOOTH "%i " LV_SYMBOL_CLOSE, active_profile_index); + lv_img_set_src(icon, &bluetooth_disconnected_right); + } + } else { + //sprintf(text, LV_SYMBOL_BLUETOOTH "%i " LV_SYMBOL_SETTINGS, active_profile_index); + //lv_img_set_src(icon, &bluetooth_advertising); + switch (active_profile_index) { + case 0: + lv_img_set_src(icon, &bluetooth_advertising_1); + break; + case 1: + lv_img_set_src(icon, &bluetooth_advertising_2); + break; + case 2: + lv_img_set_src(icon, &bluetooth_advertising_3); + break; + case 3: + lv_img_set_src(icon, &bluetooth_advertising_4); + break; + case 4: + lv_img_set_src(icon, &bluetooth_advertising_5); + break; + } + } + break; + } + + //lv_label_set_text(label, text); +} + +static void update_state() { + k_mutex_lock(&output_status_mutex, K_FOREVER); + output_status_state.selected_endpoint = zmk_endpoints_selected(); + output_status_state.active_profile_connected = zmk_ble_active_profile_is_connected(); + output_status_state.active_profile_bonded = !zmk_ble_active_profile_is_open(); + output_status_state.active_profile_index = zmk_ble_active_profile_index(); + k_mutex_unlock(&output_status_mutex); +} + +int zmk_widget_output_status_init(struct zmk_widget_output_status *widget, lv_obj_t *parent) { + output_status_init(); + update_state(); + //widget->obj = lv_label_create(parent, NULL); + widget->obj = lv_img_create(parent, NULL); + + set_status_symbol(widget->obj); + + sys_slist_append(&widgets, &widget->node); + + return 0; +} + +lv_obj_t *zmk_widget_output_status_obj(struct zmk_widget_output_status *widget) { + return widget->obj; +} + +void output_status_update_cb(struct k_work *work) { + struct zmk_widget_output_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_status_symbol(widget->obj); } +} + +K_WORK_DEFINE(output_status_update_work, output_status_update_cb); + +int output_status_listener(const zmk_event_t *eh) { + + + // Be sure we have widgets initialized before doing any work, + // since the status event can fire before display code inits. + if (!style_initialized) { + return ZMK_EV_EVENT_BUBBLE; + } + + update_state(); + + k_work_submit_to_queue(zmk_display_work_q(), &output_status_update_work); + return ZMK_EV_EVENT_BUBBLE; +} + +ZMK_LISTENER(widget_output_status, output_status_listener) +ZMK_SUBSCRIPTION(widget_output_status, zmk_endpoint_selection_changed); +#if defined(CONFIG_USB) +ZMK_SUBSCRIPTION(widget_output_status, zmk_usb_conn_state_changed); +#endif +#if defined(CONFIG_ZMK_BLE) +ZMK_SUBSCRIPTION(widget_output_status, zmk_ble_active_profile_changed); +#endif diff --git a/app/boards/arm/nrfmacro/widgets/output_status.h b/app/boards/arm/nrfmacro/widgets/output_status.h new file mode 100644 index 00000000000..d10018b15e3 --- /dev/null +++ b/app/boards/arm/nrfmacro/widgets/output_status.h @@ -0,0 +1,19 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#pragma once + +#include +#include + +struct zmk_widget_output_status { + sys_snode_t node; + lv_obj_t *obj; +}; + +int zmk_widget_output_status_init(struct zmk_widget_output_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_output_status_obj(struct zmk_widget_output_status *widget); \ No newline at end of file diff --git a/app/boards/shields/34key-common-colemak.dtsi b/app/boards/shields/34key-common-colemak.dtsi new file mode 100644 index 00000000000..3368b7a7d7d --- /dev/null +++ b/app/boards/shields/34key-common-colemak.dtsi @@ -0,0 +1,60 @@ + +#define DEFAULT 0 +#define QWERT 1 +#define NUM 2 +#define SYM 3 + +&mt { + flavor = "tap-preferred"; + tapping_term_ms = <200>; +}; + +/ { + +#include "key-common.dtsi" + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp Q &kp W &kp F &kp P &kp B &kp J &kp L &kp U &kp Y &kp SQT + &kp A &mt LSFT R &mt LALT S &mt LCTL T &kp G &kp M &mt RCTL N &mt RALT E &mt RSFT I &kp O + &kp Z &kp X &kp C &kp D &kp V &kp K &kp H &cmqus &dtsmi &kp RC(B) + < SYM TAB < NUM SPACE < NUM RET < SYM BSPC + >; + sensor-bindings = <&inc_dec_kp RIGHT LEFT &inc_dec_kp UP DOWN>; + }; + + qwert_layer { + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &kp A &mt LSFT S < SYM D < NUM F &kp G &kp H < NUM J < SYM K &mt RSFT L &kp SQT + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &cmqus &dtsmi &kp SEMI + &mt LALT TAB &mt LCTL SPACE &mt RCTL RET &mt RALT BSPC + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + number_layer { + bindings = < + &bt BT_NXT &none &kp UP &none &spc1 &kp KP_PLUS &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_MINUS + &bt BT_PRV &kp LEFT &kp DOWN &kp RIGHT &spc2 &kp KP_MULTIPLY &kp KP_N4 &kp KP_N5 &kp KP_N6 &kp KP_DIVIDE + &bt BT_CLR &none &none &none &spc3 &kp KP_EQUAL &kp KP_N1 &kp KP_N2 &kp KP_N3 &kp KP_DOT + &none &kp BSPC &kp RET &kp KP_N0 + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + symbol_layer { + bindings = < + &none &TILDE &kp LT &kp GT &kp PRCNT &kp AMPS &kp CARET &kp LBRC &kp RBRC &tog QWERT + &kp GRAVE &kp EXCL &kp MINUS &kp PLUS &kp EQUAL &kp PIPE &kp COLON &kp LPAR &kp RPAR &kp AT + &none &none &kp SLASH &kp STAR &kp BSLH &kp HASH &kp DLLR &kp LBKT &kp RBKT &none + &none &none &none &none + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + }; +}; \ No newline at end of file diff --git a/app/boards/shields/34key-common.dtsi b/app/boards/shields/34key-common.dtsi new file mode 100644 index 00000000000..d3980aa5dfc --- /dev/null +++ b/app/boards/shields/34key-common.dtsi @@ -0,0 +1,289 @@ + +#define DEFAULT 0 +#define QWERT 1 +#define NUM 2 +#define SYM 3 + +&mt { + flavor = "tap-preferred"; + tapping_term_ms = <200>; +}; + +/ { + // macros + macros { + ZMK_MACRO(hello, // hello world + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LS(H) &kp E &kp L &kp L &kp O> + , <&kp COMMA> + , <&kp W &kp O &kp R &kp L &kp D &kp EXCL>; + ) + + ZMK_MACRO(spc1, // for spacemacs window nav, Alt+M+1 + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N1>; + ) + + ZMK_MACRO(spc2, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N2>; + ) + + ZMK_MACRO(spc3, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N3>; + ) + }; + + // custom shift using mod-morph + behaviors { + cmqus: comma_question { + compatible = "zmk,behavior-mod-morph"; + label = "COMMA_QUESTION"; + #binding-cells = <0>; + bindings = <&kp COMMA>, <&kp QUESTION>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + + dtild: dot_tilde { + compatible = "zmk,behavior-mod-morph"; + label = "DOT_TILDE"; + #binding-cells = <0>; + bindings = <&kp DOT>, <&kp TILDE>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + }; + + // combos + combos { + compatible = "zmk,combos"; + // right hand + combo_esc { + timeout-ms = <50>; + key-positions = <16 17>; + bindings = <&kp ESC>; + }; + + combo_lgui { + timeout-ms = <50>; + key-positions = <5 6>; + bindings = <&kp LGUI>; + }; + + combo_fullscreen { + timeout-ms = <50>; + key-positions = <25 26>; + bindings = <&kp F11>; + }; + + combo_wkspc_up { + timeout-ms = <50>; + key-positions = <9 19>; + bindings = <&kp LC(UP)>; + }; + + combo_wkspc_down { + timeout-ms = <50>; + key-positions = <19 29>; + bindings = <&kp LC(DOWN)>; + }; + + combo_win_up { + timeout-ms = <50>; + key-positions = <7 8>; + bindings = <&kp LS(LG(UP))>; + }; + + combo_win_down { + timeout-ms = <50>; + key-positions = <27 28>; + bindings = <&kp LS(LG(DOWN))>; + }; + + combo_win_left { + timeout-ms = <50>; + key-positions = <17 18>; + bindings = <&kp LS(LG(LEFT))>; + }; + + combo_win_right { + timeout-ms = <50>; + key-positions = <9 18>; + bindings = <&kp LS(LG(RIGHT))>; + }; + + combo_rdelete { + timeout-ms = <50>; + key-positions = <15 16>; + bindings = <&kp DELETE>; + }; + + // left hand + combo_zoomin { + timeout-ms = <50>; + key-positions = <3 4>; + bindings = <&kp LC(PLUS)>; + }; + + combo_zoomout { + timeout-ms = <50>; + key-positions = <23 24>; + bindings = <&kp LC(MINUS)>; + }; + + combo_pgdn { + timeout-ms = <50>; + key-positions = <22 23>; + bindings = <&kp PG_DN>; + }; + + combo_pgup { + timeout-ms = <50>; + key-positions = <2 3>; + bindings = <&kp PG_UP>; + }; + + combo_ldelete { + timeout-ms = <50>; + key-positions = <13 14>; + bindings = <&kp DELETE>; + }; + + // symbols + combo_underscore { + timeout-ms = <50>; + key-positions = <11 12>; + bindings = <&kp UNDERSCORE>; + }; + + combo_minus { + timeout-ms = <50>; + key-positions = <12 13>; + bindings = <&kp MINUS>; + }; + + // others + combo_capswd { + timeout-ms = <50>; + key-positions = <2 7>; + bindings = <&caps_word>; + }; + + combo_lsym { + timeout-ms = <50>; + key-positions = <30 33>; + bindings = <&tog SYM>; + }; + + combo_lnum { + timeout-ms = <50>; + key-positions = <31 32>; + bindings = <&tog NUM>; + }; + + combo_hello { + timeout-ms = <50>; + key-positions = <30 31>; + bindings = <&hello>; + }; + + // output selection + // combo_outusb { + // timeout-ms = <50>; + // key-positions = <4 14>; + // bindings = <&out OUT_USB>; + // }; + + combo_outble { + timeout-ms = <50>; + key-positions = <4 14>; + bindings = <&out OUT_BLE>; + }; + + combo_outtog { + timeout-ms = <50>; + key-positions = <4 24>; + bindings = <&out OUT_TOG>; + }; + + // ble selection + combo_ble1 { + timeout-ms = <50>; + key-positions = <14 24>; + bindings = <&bt BT_SEL 0>; + }; + + combo_ble2 { + timeout-ms = <50>; + key-positions = <13 23>; + bindings = <&bt BT_SEL 1>; + }; + + combo_ble3 { + timeout-ms = <50>; + key-positions = <12 22>; + bindings = <&bt BT_SEL 2>; + }; + + combo_ble4 { + timeout-ms = <50>; + key-positions = <11 21>; + bindings = <&bt BT_SEL 3>; + }; + + combo_ble5 { + timeout-ms = <50>; + key-positions = <10 20>; + bindings = <&bt BT_SEL 4>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp Q &kp W &kp F &kp P &kp B &kp J &kp L &kp U &kp Y &kp SQT + &kp A &mt LSFT R < SYM S < NUM T &kp G &kp M < NUM N < SYM E &mt RSFT I &kp O + &kp Z &kp X &kp C &kp D &kp V &kp K &kp H &cmqus &dtild &kp SEMI + &mt LALT TAB &mt LCTL SPACE &mt RCTL RET &mt RALT BSPC + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + qwert_layer { + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &kp A &mt LSFT S < SYM D < NUM F &kp G &kp H < NUM J < SYM K &mt RSFT L &kp SQT + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &cmqus &dtild &kp SEMI + &mt LALT TAB &mt LCTL SPACE &mt RCTL RET &mt RALT BSPC + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + number_layer { + bindings = < + &bt BT_NXT &none &kp UP &none &spc1 &kp KP_PLUS &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_MINUS + &bt BT_PRV &kp LEFT &kp DOWN &kp RIGHT &spc2 &kp KP_MULTIPLY &kp KP_N4 &kp KP_N5 &kp KP_N6 &kp KP_DIVIDE + &bt BT_CLR &none &none &none &spc3 &kp KP_EQUAL &kp KP_N1 &kp KP_N2 &kp KP_N3 &kp KP_DOT + &none &kp BSPC &kp RET &kp KP_N0 + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + symbol_layer { + bindings = < + &none &none &kp LT &kp GT &kp PRCNT &kp AMPS &kp CARET &kp LBRC &kp RBRC &tog QWERT + &kp GRAVE &kp EXCL &kp MINUS &kp PLUS &kp EQUAL &kp PIPE &kp COLON &kp LPAR &kp RPAR &kp AT + &none &none &kp SLASH &kp STAR &kp BSLH &kp HASH &kp DLLR &kp LBKT &kp RBKT &none + &none &none &none &none + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + }; +}; \ No newline at end of file diff --git a/app/boards/shields/36key-common-colemak.dtsi b/app/boards/shields/36key-common-colemak.dtsi new file mode 100644 index 00000000000..ae68e7c5fd0 --- /dev/null +++ b/app/boards/shields/36key-common-colemak.dtsi @@ -0,0 +1,62 @@ +#define DEFAULT 0 +#define QWERT 1 +#define NUM 2 +#define SYM 3 + +&mt { + flavor = "tap-preferred"; + tapping_term_ms = <200>; +}; + +/ { +#include "key-common.dtsi" + + keymap { + compatible = "zmk,keymap"; + + default_layer { + label = "CLMK"; + bindings = < + &kp Q &kp W &kp F &kp P &kp B &kp J &kp L &kp U &kp Y &kp SQT + &kp A &mt LSFT R &mt LALT S &mt LCTL T < NUM G < NUM M &mt RCTL N &mt RALT E &mt RSFT I &kp O + &kp Z &kp X &kp C &kp D &kp V &kp K &kp H &cmqus &dtsmi &kp RC(B) + &encoder &kp TAB < SYM SPACE < SYM RET &kp BSPC &encoder + >; + sensor-bindings = <&inc_dec_kp RIGHT LEFT &inc_dec_kp UP DOWN>; + }; + + qwert_layer { + label = "QWRT"; + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &kp A &mt LSFT S &mt LALT D &mt LCTL T < NUM G < NUM H &mt RCTL J &mt RALT K &mt RSFT L &kp SQT + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &cmqus &dtsmi &kp RC(B) + &encoder &kp TAB < SYM SPACE < SYM RET &kp BSPC &encoder + >; + sensor-bindings = <&inc_dec_kp RIGHT LEFT &inc_dec_kp UP DOWN>; + }; + + number_layer { + label = "NUM"; + bindings = < + &bt BT_NXT &prv_tab &kp UP &nxt_tab &spc1 &kp KP_PLUS &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_MINUS + &bt BT_PRV &kp LEFT &kp DOWN &kp RIGHT &spc2 &kp KP_MULTIPLY &kp KP_N4 &kp KP_N5 &kp KP_N6 &kp KP_DIVIDE + &bt BT_CLR &none &none &none &spc3 &kp KP_EQUAL &kp KP_N1 &kp KP_N2 &kp KP_N3 &kp KP_DOT + &encoder &spc4 &kp BSPC &kp RET &kp KP_N0 &encoder + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + symbol_layer { + label = "SYM"; + bindings = < + &none &kp TILDE &kp LT &kp GT &kp PRCNT &kp AMPS &kp CARET &kp LBRC &kp RBRC &tog QWERT + &kp GRAVE &kp EXCL &kp MINUS &kp PLUS &kp EQUAL &kp PIPE &kp COLON &kp LPAR &kp RPAR &kp AT + &none &none &kp SLASH &kp STAR &kp BSLH &kp HASH &kp DLLR &kp LBKT &kp RBKT &none + &encoder &none &none &none &none &encoder + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + }; +}; \ No newline at end of file diff --git a/app/boards/shields/36key-common.dtsi b/app/boards/shields/36key-common.dtsi new file mode 100644 index 00000000000..fc6bec7fe21 --- /dev/null +++ b/app/boards/shields/36key-common.dtsi @@ -0,0 +1,299 @@ +#define DEFAULT 0 +#define COLEMAK 1 +#define NUM 2 +#define SYM 3 + +&mt { + flavor = "tap-preferred"; + tapping_term_ms = <200>; +}; + +/ { + // macros + macros { + ZMK_MACRO(hello, // hello world + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LS(H) &kp E &kp L &kp L &kp O> + , <&kp COMMA> + , <&kp W &kp O &kp R &kp L &kp D &kp EXCL>; + ) + + ZMK_MACRO(encoder, // for encoder switch press + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LS(I) &kp SPACE &kp A &kp M &kp SPACE &kp A &kp SPACE> + , <&kp E &kp N &kp C &kp O &kp D &kp E &kp R>; + ) + + ZMK_MACRO(spc1, // for spacemacs window nav, Alt+M+1 + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N1>; + ) + + ZMK_MACRO(spc2, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N2>; + ) + + ZMK_MACRO(spc3, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N3>; + ) + }; + + // custom shift using mod-morph + behaviors { + cmqus: comma_question { + compatible = "zmk,behavior-mod-morph"; + label = "COMMA_QUESTION"; + #binding-cells = <0>; + bindings = <&kp COMMA>, <&kp QUESTION>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + + dtild: dot_tilde { + compatible = "zmk,behavior-mod-morph"; + label = "DOT_TILDE"; + #binding-cells = <0>; + bindings = <&kp DOT>, <&kp TILDE>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + }; + + // combos + combos { + compatible = "zmk,combos"; + // right hand + combo_esc { + timeout-ms = <50>; + key-positions = <16 17>; + bindings = <&kp ESC>; + }; + + combo_lgui { + timeout-ms = <50>; + key-positions = <5 6>; + bindings = <&kp LGUI>; + }; + + combo_fullscreen { + timeout-ms = <50>; + key-positions = <25 26>; + bindings = <&kp F11>; + }; + + combo_wkspc_up { + timeout-ms = <50>; + key-positions = <9 19>; + bindings = <&kp LC(UP)>; + }; + + combo_wkspc_down { + timeout-ms = <50>; + key-positions = <19 29>; + bindings = <&kp LC(DOWN)>; + }; + + combo_win_up { + timeout-ms = <50>; + key-positions = <7 8>; + bindings = <&kp LS(LG(UP))>; + }; + + combo_win_down { + timeout-ms = <50>; + key-positions = <27 28>; + bindings = <&kp LS(LG(DOWN))>; + }; + + combo_win_left { + timeout-ms = <50>; + key-positions = <17 18>; + bindings = <&kp LS(LG(LEFT))>; + }; + + combo_win_right { + timeout-ms = <50>; + key-positions = <9 18>; + bindings = <&kp LS(LG(RIGHT))>; + }; + + combo_rdelete { + timeout-ms = <50>; + key-positions = <15 16>; + bindings = <&kp DELETE>; + }; + + // left hand + combo_zoomin { + timeout-ms = <50>; + key-positions = <3 4>; + bindings = <&kp LC(PLUS)>; + }; + + combo_zoomout { + timeout-ms = <50>; + key-positions = <23 24>; + bindings = <&kp LC(MINUS)>; + }; + + combo_pgdn { + timeout-ms = <50>; + key-positions = <22 23>; + bindings = <&kp PG_DN>; + }; + + combo_pgup { + timeout-ms = <50>; + key-positions = <2 3>; + bindings = <&kp PG_UP>; + }; + + combo_ldelete { + timeout-ms = <50>; + key-positions = <13 14>; + bindings = <&kp DELETE>; + }; + + // symbols + combo_underscore { + timeout-ms = <50>; + key-positions = <11 12>; + bindings = <&kp UNDERSCORE>; + }; + + combo_minus { + timeout-ms = <50>; + key-positions = <12 13>; + bindings = <&kp MINUS>; + }; + + // others + combo_capswd { + timeout-ms = <50>; + key-positions = <2 7>; + bindings = <&caps_word>; + }; + + combo_lsym { + timeout-ms = <50>; + key-positions = <31 34>; + bindings = <&tog SYM>; + }; + + combo_lnum { + timeout-ms = <50>; + key-positions = <32 33>; + bindings = <&tog NUM>; + }; + + combo_hello { + timeout-ms = <50>; + key-positions = <30 31>; + bindings = <&hello>; + }; + + // output selection + // combo_outusb { + // timeout-ms = <50>; + // key-positions = <4 14>; + // bindings = <&out OUT_USB>; + // }; + + combo_outble { + timeout-ms = <50>; + key-positions = <4 14>; + bindings = <&out OUT_BLE>; + }; + + combo_outtog { + timeout-ms = <50>; + key-positions = <4 24>; + bindings = <&out OUT_TOG>; + }; + + // ble selection + combo_ble1 { + timeout-ms = <50>; + key-positions = <14 24>; + bindings = <&bt BT_SEL 0>; + }; + + combo_ble2 { + timeout-ms = <50>; + key-positions = <13 23>; + bindings = <&bt BT_SEL 1>; + }; + + combo_ble3 { + timeout-ms = <50>; + key-positions = <12 22>; + bindings = <&bt BT_SEL 2>; + }; + + combo_ble4 { + timeout-ms = <50>; + key-positions = <11 21>; + bindings = <&bt BT_SEL 3>; + }; + + combo_ble5 { + timeout-ms = <50>; + key-positions = <10 20>; + bindings = <&bt BT_SEL 4>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + label = "QWRT"; + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &kp A &mt LSFT S < SYM D < NUM F &kp G &kp H < NUM J < SYM K &mt RSFT L &kp SQT + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &cmqus &dtild &kp SEMI + &encoder &mt LALT TAB &mt LCTL SPACE &mt RCTL RET &mt RALT BSPC &encoder + >; + sensor-bindings = <&inc_dec_kp RIGHT LEFT &inc_dec_kp UP DOWN>; + }; + + colemak_layer { + label = "CLMK"; + bindings = < + &kp Q &kp W &kp F &kp P &kp B &kp J &kp L &kp U &kp Y &kp SQT + &kp A &mt LSFT R < SYM S < NUM T &kp G &kp M < NUM N < SYM E &mt RSFT I &kp O + &kp Z &kp X &kp C &kp D &kp V &kp K &kp H &cmqus &dtild &kp SEMI + &encoder &mt LALT TAB &mt LCTL SPACE &mt RCTL RET &mt RALT BSPC &encoder + >; + sensor-bindings = <&inc_dec_kp RIGHT LEFT &inc_dec_kp UP DOWN>; + }; + + number_layer { + label = "NUM"; + bindings = < + &bt BT_NXT &none &kp UP &none &spc1 &kp KP_PLUS &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_MINUS + &bt BT_PRV &kp LEFT &kp DOWN &kp RIGHT &spc2 &kp KP_MULTIPLY &kp KP_N4 &kp KP_N5 &kp KP_N6 &kp KP_DIVIDE + &bt BT_CLR &none &none &none &spc3 &kp KP_EQUAL &kp KP_N1 &kp KP_N2 &kp KP_N3 &kp KP_DOT + &encoder &spc4 &kp BSPC &kp RET &kp KP_N0 &encoder + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + symbol_layer { + label = "SYM"; + bindings = < + &none &none &kp LT &kp GT &kp PRCNT &kp AMPS &kp CARET &kp LBRC &kp RBRC &tog COLEMAK + &kp GRAVE &kp EXCL &kp MINUS &kp PLUS &kp EQUAL &kp PIPE &kp COLON &kp LPAR &kp RPAR &kp AT + &none &none &kp SLASH &kp STAR &kp BSLH &kp HASH &kp DLLR &kp LBKT &kp RBKT &none + &encoder &none &none &none &none &encoder + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + }; +}; \ No newline at end of file diff --git a/app/boards/shields/40key-common-colemak.dtsi b/app/boards/shields/40key-common-colemak.dtsi new file mode 100644 index 00000000000..958a9200a9b --- /dev/null +++ b/app/boards/shields/40key-common-colemak.dtsi @@ -0,0 +1,63 @@ +#define DEFAULT 0 +#define QWERT 1 +#define NUM 2 +#define SYM 3 + +&mt { + flavor = "tap-preferred"; + tapping_term_ms = <200>; +}; + +/ { +#include "key-common.dtsi" + + keymap { + compatible = "zmk,keymap"; + + default_layer { + label = "CLMK"; + bindings = < + &kp Q &kp W &kp F &kp P &kp B &kp J &kp L &kp U &kp Y &kp SQT + &kp A &mt LSFT R &mt LALT S &mt LCTL T < NUM G < NUM M &mt RCTL N &mt RALT E &mt RSFT I &kp O + &kp Z &kp X &kp C &kp D &kp V &kp K &kp H &cmqus &dtsmi &kp RC(B) + &kp KP_N1 &kp KP_N2 &encoder &kp TAB < SYM SPACE < SYM RET &kp BSPC &encoder &kp KP_N3 &kp KP_N4 + >; + sensor-bindings = <&inc_dec_kp RIGHT LEFT &inc_dec_kp UP DOWN>; + }; + + qwert_layer { + label = "QWRT"; + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &kp A &mt LSFT S &mt LALT D &mt LCTL T < NUM G < NUM H &mt RCTL J &mt RALT K &mt RSFT L &kp SQT + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &cmqus &dtsmi &kp RC(B) + &kp KP_N1 &kp KP_N2 &encoder &kp TAB < SYM SPACE < SYM RET &kp BSPC &encoder &kp KP_N3 &kp KP_N4 + &encoder &kp TAB < SYM SPACE < SYM RET &kp BSPC &encoder + >; + sensor-bindings = <&inc_dec_kp RIGHT LEFT &inc_dec_kp UP DOWN>; + }; + + number_layer { + label = "NUM"; + bindings = < + &bt BT_NXT &prv_tab &kp UP &nxt_tab &spc1 &kp KP_PLUS &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_MINUS + &bt BT_PRV &kp LEFT &kp DOWN &kp RIGHT &spc2 &kp KP_MULTIPLY &kp KP_N4 &kp KP_N5 &kp KP_N6 &kp KP_DIVIDE + &bt BT_CLR &none &none &none &spc3 &kp KP_EQUAL &kp KP_N1 &kp KP_N2 &kp KP_N3 &kp KP_DOT + &kp KP_N1 &kp KP_N2 &encoder &spc4 &kp BSPC &kp RET &kp KP_N0 &encoder &kp KP_N3 &kp KP_N4 + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + symbol_layer { + label = "SYM"; + bindings = < + &none &kp TILDE &kp LT &kp GT &kp PRCNT &kp AMPS &kp CARET &kp LBRC &kp RBRC &tog QWERT + &kp GRAVE &kp EXCL &kp MINUS &kp PLUS &kp EQUAL &kp PIPE &kp COLON &kp LPAR &kp RPAR &kp AT + &none &none &kp SLASH &kp STAR &kp BSLH &kp HASH &kp DLLR &kp LBKT &kp RBKT &none + &none &none &encoder &none &none &none &none &encoder &none &none + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + }; +}; \ No newline at end of file diff --git a/app/boards/shields/40key-common.dtsi b/app/boards/shields/40key-common.dtsi new file mode 100644 index 00000000000..fc6bec7fe21 --- /dev/null +++ b/app/boards/shields/40key-common.dtsi @@ -0,0 +1,299 @@ +#define DEFAULT 0 +#define COLEMAK 1 +#define NUM 2 +#define SYM 3 + +&mt { + flavor = "tap-preferred"; + tapping_term_ms = <200>; +}; + +/ { + // macros + macros { + ZMK_MACRO(hello, // hello world + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LS(H) &kp E &kp L &kp L &kp O> + , <&kp COMMA> + , <&kp W &kp O &kp R &kp L &kp D &kp EXCL>; + ) + + ZMK_MACRO(encoder, // for encoder switch press + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LS(I) &kp SPACE &kp A &kp M &kp SPACE &kp A &kp SPACE> + , <&kp E &kp N &kp C &kp O &kp D &kp E &kp R>; + ) + + ZMK_MACRO(spc1, // for spacemacs window nav, Alt+M+1 + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N1>; + ) + + ZMK_MACRO(spc2, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N2>; + ) + + ZMK_MACRO(spc3, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N3>; + ) + }; + + // custom shift using mod-morph + behaviors { + cmqus: comma_question { + compatible = "zmk,behavior-mod-morph"; + label = "COMMA_QUESTION"; + #binding-cells = <0>; + bindings = <&kp COMMA>, <&kp QUESTION>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + + dtild: dot_tilde { + compatible = "zmk,behavior-mod-morph"; + label = "DOT_TILDE"; + #binding-cells = <0>; + bindings = <&kp DOT>, <&kp TILDE>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + }; + + // combos + combos { + compatible = "zmk,combos"; + // right hand + combo_esc { + timeout-ms = <50>; + key-positions = <16 17>; + bindings = <&kp ESC>; + }; + + combo_lgui { + timeout-ms = <50>; + key-positions = <5 6>; + bindings = <&kp LGUI>; + }; + + combo_fullscreen { + timeout-ms = <50>; + key-positions = <25 26>; + bindings = <&kp F11>; + }; + + combo_wkspc_up { + timeout-ms = <50>; + key-positions = <9 19>; + bindings = <&kp LC(UP)>; + }; + + combo_wkspc_down { + timeout-ms = <50>; + key-positions = <19 29>; + bindings = <&kp LC(DOWN)>; + }; + + combo_win_up { + timeout-ms = <50>; + key-positions = <7 8>; + bindings = <&kp LS(LG(UP))>; + }; + + combo_win_down { + timeout-ms = <50>; + key-positions = <27 28>; + bindings = <&kp LS(LG(DOWN))>; + }; + + combo_win_left { + timeout-ms = <50>; + key-positions = <17 18>; + bindings = <&kp LS(LG(LEFT))>; + }; + + combo_win_right { + timeout-ms = <50>; + key-positions = <9 18>; + bindings = <&kp LS(LG(RIGHT))>; + }; + + combo_rdelete { + timeout-ms = <50>; + key-positions = <15 16>; + bindings = <&kp DELETE>; + }; + + // left hand + combo_zoomin { + timeout-ms = <50>; + key-positions = <3 4>; + bindings = <&kp LC(PLUS)>; + }; + + combo_zoomout { + timeout-ms = <50>; + key-positions = <23 24>; + bindings = <&kp LC(MINUS)>; + }; + + combo_pgdn { + timeout-ms = <50>; + key-positions = <22 23>; + bindings = <&kp PG_DN>; + }; + + combo_pgup { + timeout-ms = <50>; + key-positions = <2 3>; + bindings = <&kp PG_UP>; + }; + + combo_ldelete { + timeout-ms = <50>; + key-positions = <13 14>; + bindings = <&kp DELETE>; + }; + + // symbols + combo_underscore { + timeout-ms = <50>; + key-positions = <11 12>; + bindings = <&kp UNDERSCORE>; + }; + + combo_minus { + timeout-ms = <50>; + key-positions = <12 13>; + bindings = <&kp MINUS>; + }; + + // others + combo_capswd { + timeout-ms = <50>; + key-positions = <2 7>; + bindings = <&caps_word>; + }; + + combo_lsym { + timeout-ms = <50>; + key-positions = <31 34>; + bindings = <&tog SYM>; + }; + + combo_lnum { + timeout-ms = <50>; + key-positions = <32 33>; + bindings = <&tog NUM>; + }; + + combo_hello { + timeout-ms = <50>; + key-positions = <30 31>; + bindings = <&hello>; + }; + + // output selection + // combo_outusb { + // timeout-ms = <50>; + // key-positions = <4 14>; + // bindings = <&out OUT_USB>; + // }; + + combo_outble { + timeout-ms = <50>; + key-positions = <4 14>; + bindings = <&out OUT_BLE>; + }; + + combo_outtog { + timeout-ms = <50>; + key-positions = <4 24>; + bindings = <&out OUT_TOG>; + }; + + // ble selection + combo_ble1 { + timeout-ms = <50>; + key-positions = <14 24>; + bindings = <&bt BT_SEL 0>; + }; + + combo_ble2 { + timeout-ms = <50>; + key-positions = <13 23>; + bindings = <&bt BT_SEL 1>; + }; + + combo_ble3 { + timeout-ms = <50>; + key-positions = <12 22>; + bindings = <&bt BT_SEL 2>; + }; + + combo_ble4 { + timeout-ms = <50>; + key-positions = <11 21>; + bindings = <&bt BT_SEL 3>; + }; + + combo_ble5 { + timeout-ms = <50>; + key-positions = <10 20>; + bindings = <&bt BT_SEL 4>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + label = "QWRT"; + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &kp A &mt LSFT S < SYM D < NUM F &kp G &kp H < NUM J < SYM K &mt RSFT L &kp SQT + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &cmqus &dtild &kp SEMI + &encoder &mt LALT TAB &mt LCTL SPACE &mt RCTL RET &mt RALT BSPC &encoder + >; + sensor-bindings = <&inc_dec_kp RIGHT LEFT &inc_dec_kp UP DOWN>; + }; + + colemak_layer { + label = "CLMK"; + bindings = < + &kp Q &kp W &kp F &kp P &kp B &kp J &kp L &kp U &kp Y &kp SQT + &kp A &mt LSFT R < SYM S < NUM T &kp G &kp M < NUM N < SYM E &mt RSFT I &kp O + &kp Z &kp X &kp C &kp D &kp V &kp K &kp H &cmqus &dtild &kp SEMI + &encoder &mt LALT TAB &mt LCTL SPACE &mt RCTL RET &mt RALT BSPC &encoder + >; + sensor-bindings = <&inc_dec_kp RIGHT LEFT &inc_dec_kp UP DOWN>; + }; + + number_layer { + label = "NUM"; + bindings = < + &bt BT_NXT &none &kp UP &none &spc1 &kp KP_PLUS &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_MINUS + &bt BT_PRV &kp LEFT &kp DOWN &kp RIGHT &spc2 &kp KP_MULTIPLY &kp KP_N4 &kp KP_N5 &kp KP_N6 &kp KP_DIVIDE + &bt BT_CLR &none &none &none &spc3 &kp KP_EQUAL &kp KP_N1 &kp KP_N2 &kp KP_N3 &kp KP_DOT + &encoder &spc4 &kp BSPC &kp RET &kp KP_N0 &encoder + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + symbol_layer { + label = "SYM"; + bindings = < + &none &none &kp LT &kp GT &kp PRCNT &kp AMPS &kp CARET &kp LBRC &kp RBRC &tog COLEMAK + &kp GRAVE &kp EXCL &kp MINUS &kp PLUS &kp EQUAL &kp PIPE &kp COLON &kp LPAR &kp RPAR &kp AT + &none &none &kp SLASH &kp STAR &kp BSLH &kp HASH &kp DLLR &kp LBKT &kp RBKT &none + &encoder &none &none &none &none &encoder + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + }; +}; \ No newline at end of file diff --git a/app/boards/shields/42key-common-colemak.dtsi b/app/boards/shields/42key-common-colemak.dtsi new file mode 100644 index 00000000000..d0ff9eafc64 --- /dev/null +++ b/app/boards/shields/42key-common-colemak.dtsi @@ -0,0 +1,291 @@ +#define DEFAULT 0 +#define NUM 1 +#define SYM 2 + +&mt { + flavor = "tap-preferred"; + tapping_term_ms = <200>; +}; + +/ { + + // macros + macros { + ZMK_MACRO(hello, // hello world + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LS(H) &kp E &kp L &kp L &kp O> + , <&kp COMMA> + , <&kp W &kp O &kp R &kp L &kp D &kp EXCL>; + ) + + ZMK_MACRO(encoder, // for encoder switch press + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LS(I) &kp SPACE &kp A &kp M &kp SPACE &kp A &kp SPACE> + , <&kp E &kp N &kp C &kp O &kp D &kp E &kp R>; + ) + + ZMK_MACRO(spc1, // for spacemacs window nav, Alt+M+1 + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N1>; + ) + + ZMK_MACRO(spc2, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N2>; + ) + + ZMK_MACRO(spc3, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N3>; + ) + }; + + // custom shift using mod-morph + // behaviors { + // cmqus: comma_question { + // compatible = "zmk,behavior-mod-morph"; + // label = "COMMA_QUESTION"; + // #binding-cells = <0>; + // bindings = <&kp COMMA>, <&kp QUESTION>; + // mods = <(MOD_LSFT|MOD_RSFT)>; + // }; + + // dtild: dot_tilde { + // compatible = "zmk,behavior-mod-morph"; + // label = "DOT_TILDE"; + // #binding-cells = <0>; + // bindings = <&kp DOT>, <&kp TILDE>; + // mods = <(MOD_LSFT|MOD_RSFT)>; + // }; + // }; + + // combos + combos { + compatible = "zmk,combos"; + // right hand + combo_esc { + timeout-ms = <50>; + key-positions = <19 20>; + bindings = <&kp ESC>; + }; + + combo_lgui { + timeout-ms = <50>; + key-positions = <6 7>; + bindings = <&kp LGUI>; + }; + + combo_fullscreen { + timeout-ms = <50>; + key-positions = <30 31>; + bindings = <&kp F11>; + }; + + combo_wkspc_up { + timeout-ms = <50>; + key-positions = <11 23>; + bindings = <&kp LC(UP)>; + }; + + combo_wkspc_down { + timeout-ms = <50>; + key-positions = <23 35>; + bindings = <&kp LC(DOWN)>; + }; + + combo_win_up { + timeout-ms = <50>; + key-positions = <9 10>; + bindings = <&kp LS(LG(UP))>; + }; + + combo_win_down { + timeout-ms = <50>; + key-positions = <33 34>; + bindings = <&kp LS(LG(DOWN))>; + }; + + combo_win_left { + timeout-ms = <50>; + key-positions = <21 22>; + bindings = <&kp LS(LG(LEFT))>; + }; + + combo_win_right { + timeout-ms = <50>; + key-positions = <22 23>; + bindings = <&kp LS(LG(RIGHT))>; + }; + + combo_rdelete { + timeout-ms = <50>; + key-positions = <18 19>; + bindings = <&kp DELETE>; + }; + + // left hand + combo_zoomin { + timeout-ms = <50>; + key-positions = <4 5>; + bindings = <&kp LC(PLUS)>; + }; + + combo_zoomout { + timeout-ms = <50>; + key-positions = <28 29>; + bindings = <&kp LC(MINUS)>; + }; + + combo_pgdn { + timeout-ms = <50>; + key-positions = <27 28>; + bindings = <&kp PG_DN>; + }; + + combo_pgup { + timeout-ms = <50>; + key-positions = <3 4>; + bindings = <&kp PG_UP>; + }; + + combo_ldelete { + timeout-ms = <50>; + key-positions = <16 17>; + bindings = <&kp DELETE>; + }; + + // symbols + combo_underscore { + timeout-ms = <50>; + key-positions = <14 15>; + bindings = <&kp UNDERSCORE>; + }; + + combo_minus { + timeout-ms = <50>; + key-positions = <15 16>; + bindings = <&kp MINUS>; + }; + + // others + combo_capswd { + timeout-ms = <50>; + key-positions = <3 8>; + bindings = <&caps_word>; + }; + + combo_lsym { + timeout-ms = <50>; + key-positions = <37 40>; + bindings = <&tog SYM>; + }; + + combo_lnum { + timeout-ms = <50>; + key-positions = <38 39>; + bindings = <&tog NUM>; + }; + + combo_hello { + timeout-ms = <50>; + key-positions = <37 38>; + bindings = <&hello>; + }; + + combo_outble { + timeout-ms = <50>; + key-positions = <5 17>; + bindings = <&out OUT_BLE>; + }; + + combo_outtog { + timeout-ms = <50>; + key-positions = <5 29>; + bindings = <&out OUT_TOG>; + }; + + // ble selection + combo_ble1 { + timeout-ms = <50>; + key-positions = <17 29>; + bindings = <&bt BT_SEL 0>; + }; + + combo_ble2 { + timeout-ms = <50>; + key-positions = <16 28>; + bindings = <&bt BT_SEL 1>; + }; + + combo_ble3 { + timeout-ms = <50>; + key-positions = <15 27>; + bindings = <&bt BT_SEL 2>; + }; + + combo_ble4 { + timeout-ms = <50>; + key-positions = <14 26>; + bindings = <&bt BT_SEL 3>; + }; + + combo_ble5 { + timeout-ms = <50>; + key-positions = <13 25>; + bindings = <&bt BT_SEL 4>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + label = "CLMK"; +// ----------------------------------------------------------------------------------------- +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BKSP | +// | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHFT | Z | X | C | V | B | | N | M | , | . | / | ESC | +// | GUI | LWR | SPC | | ENT | RSE | ALT | + bindings = < + &kp TAB &kp Q &kp W &kp F &kp P &kp B &kp J &kp L &kp U &kp Y &kp SEMI &kp BSPC + &kp N0 &kp A &kp R &kp S &kp T &kp G &kp N &kp M &kp E &kp I &kp O &kp SQT + &kp N1 &kp Z &kp X &kp C &kp D &kp V &kp K &kp H &kp COMMA &kp DOT &kp FSLH &kp N3 + &kp LGUI < NUM N5 &kp SPACE &kp RET < SYM N6 &kp RALT + >; + }; + lower_layer { + label = "NUM"; +// ----------------------------------------------------------------------------------------- +// | TAB | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | BKSP | +// | BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 | | LFT | DWN | UP | RGT | | | +// | SHFT | | | | | | | | | | | | | +// | GUI | | SPC | | ENT | | ALT | + bindings = < + &kp TAB &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSPC + &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &kp LEFT &kp DOWN &kp UP &kp RIGHT &trans &trans + &kp LSHFT &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &kp LGUI &trans &kp SPACE &kp RET &trans &kp RALT + >; + }; + + raise_layer { + label = "SYM"; +// ----------------------------------------------------------------------------------------- +// | TAB | ! | @ | # | $ | % | | ^ | & | * | ( | ) | BKSP | +// | CTRL | | | | | | | - | = | [ | ] | \ | ` | +// | SHFT | | | | | | | _ | + | { | } | "|" | ~ | +// | GUI | | SPC | | ENT | | ALT | + bindings = < + &kp TAB &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp KP_MULTIPLY &kp LPAR &kp RPAR &kp BSPC + &kp LCTRL &trans &trans &trans &trans &trans &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH &kp GRAVE + &kp LSHFT &trans &trans &trans &trans &trans &kp UNDER &kp PLUS &kp LBRC &kp RBRC &kp PIPE &kp TILDE + &kp LGUI &trans &kp SPACE &kp RET &trans &kp RALT + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/42key-common.dtsi b/app/boards/shields/42key-common.dtsi new file mode 100644 index 00000000000..94ddf42384d --- /dev/null +++ b/app/boards/shields/42key-common.dtsi @@ -0,0 +1,291 @@ +#define DEFAULT 0 +#define NUM 1 +#define SYM 2 + +&mt { + flavor = "tap-preferred"; + tapping_term_ms = <200>; +}; + +/ { + + // macros + macros { + ZMK_MACRO(hello, // hello world + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LS(H) &kp E &kp L &kp L &kp O> + , <&kp COMMA> + , <&kp W &kp O &kp R &kp L &kp D &kp EXCL>; + ) + + ZMK_MACRO(encoder, // for encoder switch press + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LS(I) &kp SPACE &kp A &kp M &kp SPACE &kp A &kp SPACE> + , <&kp E &kp N &kp C &kp O &kp D &kp E &kp R>; + ) + + ZMK_MACRO(spc1, // for spacemacs window nav, Alt+M+1 + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N1>; + ) + + ZMK_MACRO(spc2, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N2>; + ) + + ZMK_MACRO(spc3, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N3>; + ) + }; + + // custom shift using mod-morph + // behaviors { + // cmqus: comma_question { + // compatible = "zmk,behavior-mod-morph"; + // label = "COMMA_QUESTION"; + // #binding-cells = <0>; + // bindings = <&kp COMMA>, <&kp QUESTION>; + // mods = <(MOD_LSFT|MOD_RSFT)>; + // }; + + // dtild: dot_tilde { + // compatible = "zmk,behavior-mod-morph"; + // label = "DOT_TILDE"; + // #binding-cells = <0>; + // bindings = <&kp DOT>, <&kp TILDE>; + // mods = <(MOD_LSFT|MOD_RSFT)>; + // }; + // }; + + // combos + combos { + compatible = "zmk,combos"; + // right hand + combo_esc { + timeout-ms = <50>; + key-positions = <19 20>; + bindings = <&kp ESC>; + }; + + combo_lgui { + timeout-ms = <50>; + key-positions = <6 7>; + bindings = <&kp LGUI>; + }; + + combo_fullscreen { + timeout-ms = <50>; + key-positions = <30 31>; + bindings = <&kp F11>; + }; + + combo_wkspc_up { + timeout-ms = <50>; + key-positions = <11 23>; + bindings = <&kp LC(UP)>; + }; + + combo_wkspc_down { + timeout-ms = <50>; + key-positions = <23 35>; + bindings = <&kp LC(DOWN)>; + }; + + combo_win_up { + timeout-ms = <50>; + key-positions = <9 10>; + bindings = <&kp LS(LG(UP))>; + }; + + combo_win_down { + timeout-ms = <50>; + key-positions = <33 34>; + bindings = <&kp LS(LG(DOWN))>; + }; + + combo_win_left { + timeout-ms = <50>; + key-positions = <21 22>; + bindings = <&kp LS(LG(LEFT))>; + }; + + combo_win_right { + timeout-ms = <50>; + key-positions = <22 23>; + bindings = <&kp LS(LG(RIGHT))>; + }; + + combo_rdelete { + timeout-ms = <50>; + key-positions = <18 19>; + bindings = <&kp DELETE>; + }; + + // left hand + combo_zoomin { + timeout-ms = <50>; + key-positions = <4 5>; + bindings = <&kp LC(PLUS)>; + }; + + combo_zoomout { + timeout-ms = <50>; + key-positions = <28 29>; + bindings = <&kp LC(MINUS)>; + }; + + combo_pgdn { + timeout-ms = <50>; + key-positions = <27 28>; + bindings = <&kp PG_DN>; + }; + + combo_pgup { + timeout-ms = <50>; + key-positions = <3 4>; + bindings = <&kp PG_UP>; + }; + + combo_ldelete { + timeout-ms = <50>; + key-positions = <16 17>; + bindings = <&kp DELETE>; + }; + + // symbols + combo_underscore { + timeout-ms = <50>; + key-positions = <14 15>; + bindings = <&kp UNDERSCORE>; + }; + + combo_minus { + timeout-ms = <50>; + key-positions = <15 16>; + bindings = <&kp MINUS>; + }; + + // others + combo_capswd { + timeout-ms = <50>; + key-positions = <3 8>; + bindings = <&caps_word>; + }; + + combo_lsym { + timeout-ms = <50>; + key-positions = <37 40>; + bindings = <&tog SYM>; + }; + + combo_lnum { + timeout-ms = <50>; + key-positions = <38 39>; + bindings = <&tog NUM>; + }; + + combo_hello { + timeout-ms = <50>; + key-positions = <37 38>; + bindings = <&hello>; + }; + + combo_outble { + timeout-ms = <50>; + key-positions = <5 17>; + bindings = <&out OUT_BLE>; + }; + + combo_outtog { + timeout-ms = <50>; + key-positions = <5 29>; + bindings = <&out OUT_TOG>; + }; + + // ble selection + combo_ble1 { + timeout-ms = <50>; + key-positions = <17 29>; + bindings = <&bt BT_SEL 0>; + }; + + combo_ble2 { + timeout-ms = <50>; + key-positions = <16 28>; + bindings = <&bt BT_SEL 1>; + }; + + combo_ble3 { + timeout-ms = <50>; + key-positions = <15 27>; + bindings = <&bt BT_SEL 2>; + }; + + combo_ble4 { + timeout-ms = <50>; + key-positions = <14 26>; + bindings = <&bt BT_SEL 3>; + }; + + combo_ble5 { + timeout-ms = <50>; + key-positions = <13 25>; + bindings = <&bt BT_SEL 4>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + label = "QWTY"; +// ----------------------------------------------------------------------------------------- +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BKSP | +// | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHFT | Z | X | C | V | B | | N | M | , | . | / | ESC | +// | GUI | LWR | SPC | | ENT | RSE | ALT | + bindings = < + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC + &kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp ESC + &kp LGUI &mo NUM &kp SPACE &kp RET &mo SYM &kp RALT + >; + }; + lower_layer { + label = "NUM"; +// ----------------------------------------------------------------------------------------- +// | TAB | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | BKSP | +// | BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 | | LFT | DWN | UP | RGT | | | +// | SHFT | | | | | | | | | | | | | +// | GUI | | SPC | | ENT | | ALT | + bindings = < + &kp TAB &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSPC + &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &kp LEFT &kp DOWN &kp UP &kp RIGHT &trans &trans + &kp LSHFT &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &kp LGUI &trans &kp SPACE &kp RET &trans &kp RALT + >; + }; + + raise_layer { + label = "SYM"; +// ----------------------------------------------------------------------------------------- +// | TAB | ! | @ | # | $ | % | | ^ | & | * | ( | ) | BKSP | +// | CTRL | | | | | | | - | = | [ | ] | \ | ` | +// | SHFT | | | | | | | _ | + | { | } | "|" | ~ | +// | GUI | | SPC | | ENT | | ALT | + bindings = < + &kp TAB &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp KP_MULTIPLY &kp LPAR &kp RPAR &kp BSPC + &kp LCTRL &trans &trans &trans &trans &trans &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH &kp GRAVE + &kp LSHFT &trans &trans &trans &trans &trans &kp UNDER &kp PLUS &kp LBRC &kp RBRC &kp PIPE &kp TILDE + &kp LGUI &trans &kp SPACE &kp RET &trans &kp RALT + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/blade/Kconfig.defconfig b/app/boards/shields/blade/Kconfig.defconfig new file mode 100644 index 00000000000..039a70f92fa --- /dev/null +++ b/app/boards/shields/blade/Kconfig.defconfig @@ -0,0 +1,32 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BLADE_RIGHT + +config ZMK_KEYBOARD_NAME + default "Blade" + +config ZMK_SPLIT_BLE_ROLE_CENTRAL + default y + +endif + +if BLADE_LEFT +config ZMK_KEYBOARD_NAME + default "Blade-slave" + +endif + +if BLADE_LEFT || BLADE_RIGHT + +config ZMK_SPLIT + default y + +config ZMK_USB + default y + +config NRFMACRO_MARKLOGO_NAME + string "Source file name of the shield mark logo" + default "sweepro-marklogo.c" +endif + diff --git a/app/boards/shields/blade/Kconfig.shield b/app/boards/shields/blade/Kconfig.shield new file mode 100644 index 00000000000..9a54bef2267 --- /dev/null +++ b/app/boards/shields/blade/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BLADE_LEFT + def_bool $(shields_list_contains,blade_left) + +config BLADE_RIGHT + def_bool $(shields_list_contains,blade_right) diff --git a/app/boards/shields/blade/blade.dtsi b/app/boards/shields/blade/blade.dtsi new file mode 100644 index 00000000000..4f2af147b3e --- /dev/null +++ b/app/boards/shields/blade/blade.dtsi @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/* blade-specific: common settings */ +/ { + + chosen: chosen { + zmk,kscan = &kscan; + zmk,matrix_transform = &default_transform; + }; + +/* global matrix transform */ + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <5>; + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) + RC(4,5) RC(4,6) RC(4,7) + >; + + }; + + /* Scan matrix declaration */ + kscan: kscan { + compatible = "zmk,kscan-composite"; + label = "KSCAN"; + rows = <5>; + columns = <10>; + + /* There is a key matrix by default */ + normal_keys { + kscan = <&kscan0>; + }; + }; + + /* Configure sliders (both split can have a slider) */ + sliders { + compatible = "zmk,keymap-sliders"; + sliders = <&slider_left &slider_right>; + }; + + /* Configure trackballs (either split can have the trackball) */ + trackballs { + compatible = "zmk,keymap-trackballs"; + trackballs = <&trackball>; + }; + + /* Configure encoders (both splits can have a encoder) */ + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&encoder_left &encoder_right>; + }; + + // define the two encoders + encoder_left: encoder_left { + compatible = "alps,ec11"; + status = "disabled"; + label = "LEFT_ENCODER"; + resolution = <2>; + }; + + encoder_right: encoder_right { + compatible = "alps,ec11"; + status = "disabled"; + label = "RIGHT_ENCODER"; + resolution = <2>; + }; +}; + +/* Declare the two sliders */ +&i2c0 { + compatible = "nordic,nrf-twi"; + status = "okay"; + + slider_left: slider_left@28 { + compatible = "zmk,kscan-cap1203"; + label = "SLIDER_LEFT"; + status = "disabled"; + reg = <0x28>; + }; + + slider_right: slider_right@28 { + compatible = "zmk,kscan-cap1203"; + label = "SLIDER_RIGHT"; + status = "disabled"; + reg = <0x28>; + }; + +}; + +/* Declare the trackball */ +&spi2 { + compatible = "nordic,nrf-spim"; + + trackball: trackball@0 { + compatible = "pixart,pmw3610"; + status = "disabled"; + reg = <0>; + label = "TRACKBALL"; + spi-max-frequency = <2000000>; + duplex = <2048>; // required by 3-wire spi + }; +}; diff --git a/app/boards/shields/blade/blade.keymap b/app/boards/shields/blade/blade.keymap new file mode 100644 index 00000000000..b4c5d66ae23 --- /dev/null +++ b/app/boards/shields/blade/blade.keymap @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +#define DEFAULT 0 +#define NUM 1 +#define SYM 2 +#define FUN 3 +#define PTD_CRS 4 +#define PTD_NAV 5 +#define PTD_HOR 6 +#define PTD_VER 7 +#define PTD_FIN 8 + +&mt { + flavor = "tap-preferred"; + tapping_term_ms = <200>; +}; + +/ { + // macros + macros { + ZMK_MACRO(hello, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp H &kp E &kp L &kp L &kp O>; + ) + + ZMK_MACRO(encoder, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp E &kp N &kp C &kp O &kp D &kp E &kp R>; + ) + + ZMK_MACRO(spc1, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N1>; + ) + + ZMK_MACRO(spc2, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N2>; + ) + + ZMK_MACRO(spc3, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N3>; + ) + + ZMK_MACRO(spc4, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N4>; + ) + + ZMK_MACRO(nxt_tab, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LC(TAB)>; + ) + + ZMK_MACRO(prv_tab, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LC(LS(TAB))>; + ) + }; + + // custom shift using mod-morph + behaviors { + cmqus: comma_question { + compatible = "zmk,behavior-mod-morph"; + label = "COMMA_QUESTION"; + #binding-cells = <0>; + bindings = <&kp COMMA>, <&kp QUESTION>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + + dtsmi: dot_semi { + compatible = "zmk,behavior-mod-morph"; + label = "DOT_SEMI"; + #binding-cells = <0>; + bindings = <&kp DOT>, <&kp SEMI>; + mods = <(MOD_LSFT|MOD_RSFT)>; + masked_mods = <(MOD_LSFT|MOD_RSFT)>; // don't send shift + }; + }; + + // combos + combos { + compatible = "zmk,combos"; + // right hand + combo_esc { + timeout-ms = <50>; + key-positions = <16 17>; + bindings = <&kp ESC>; + }; + + combo_lgui { + timeout-ms = <50>; + key-positions = <5 6>; + bindings = <&kp LGUI>; + }; + + combo_fullscreen { + timeout-ms = <50>; + key-positions = <25 26>; + bindings = <&kp F11>; + }; + + combo_wkspc_up { + timeout-ms = <50>; + key-positions = <6 7>; + bindings = <&kp LG(PG_UP)>; + }; + + combo_wkspc_down { + timeout-ms = <50>; + key-positions = <26 27>; + bindings = <&kp LG(PG_DN)>; + }; + + combo_win_up { + timeout-ms = <50>; + key-positions = <7 8>; + bindings = <&kp LS(LG(PG_UP))>; + }; + + combo_win_down { + timeout-ms = <50>; + key-positions = <27 28>; + bindings = <&kp LS(LG(PG_DN))>; + }; + + combo_win_left { + timeout-ms = <50>; + key-positions = <17 18>; + bindings = <&kp LS(LG(LEFT))>; + }; + + combo_win_right { + timeout-ms = <50>; + key-positions = <9 18>; + bindings = <&kp LS(LG(RIGHT))>; + }; + + combo_rdelete { + timeout-ms = <50>; + key-positions = <15 16>; + bindings = <&kp DELETE>; + }; + + // left hand + combo_ldelete { + timeout-ms = <50>; + key-positions = <13 14>; + bindings = <&kp DELETE>; + }; + + combo_zoomin { + timeout-ms = <50>; + key-positions = <3 4>; + bindings = <&kp LC(PLUS)>; + }; + + combo_zoomout { + timeout-ms = <50>; + key-positions = <23 24>; + bindings = <&kp LC(MINUS)>; + }; + + combo_pgdn { + timeout-ms = <50>; + key-positions = <21 22>; + bindings = <&kp PG_DN>; + }; + + combo_pgup { + timeout-ms = <50>; + key-positions = <1 2>; + bindings = <&kp PG_UP>; + }; + + combo_mb_lclick { + timeout-ms = <50>; + key-positions = <12 13>; + bindings = <&mkp LCLK>; + }; + + combo_mb_rclick { + timeout-ms = <50>; + key-positions = <22 23>; + bindings = <&mkp RCLK>; + }; + + combo_mb_mclick { + timeout-ms = <50>; + key-positions = <2 3>; + bindings = <&mkp MCLK>; + }; + + // symbols + combo_underscore { + timeout-ms = <50>; + key-positions = <11 12>; + bindings = <&kp UNDERSCORE>; + }; + + // others + combo_capswd { + timeout-ms = <50>; + key-positions = <2 7>; + bindings = <&caps_word>; + }; + + // output selection + combo_outble { + timeout-ms = <50>; + key-positions = <4 14>; + bindings = <&out OUT_USB>; + }; + + combo_outtog { + timeout-ms = <50>; + key-positions = <4 24>; + bindings = <&out OUT_TOG>; + }; + + // ble selection + combo_ble1 { + timeout-ms = <50>; + key-positions = <14 24>; + bindings = <&bt BT_SEL 0>; + }; + + combo_ble2 { + timeout-ms = <50>; + key-positions = <13 23>; + bindings = <&bt BT_SEL 1>; + }; + + combo_ble3 { + timeout-ms = <50>; + key-positions = <12 22>; + bindings = <&bt BT_SEL 2>; + }; + + combo_ble4 { + timeout-ms = <50>; + key-positions = <11 21>; + bindings = <&bt BT_SEL 3>; + }; + + combo_ble5 { + timeout-ms = <50>; + key-positions = <10 20>; + bindings = <&bt BT_SEL 4>; + }; + }; + +// keymap + keymap { + compatible = "zmk,keymap"; + + default_layer { + label = "CLMK"; + bindings = < + < PTD_NAV Q &kp W &kp F &kp P &kp B &kp J &kp L &kp U &kp Y < PTD_NAV SQT + < SYM A &mt LALT R &mt LSFT S &mt LCTL T &kp G &kp M &mt RCTL N &mt RSFT E &mt RALT I < SYM O + < PTD_HOR Z < PTD_VER X < PTD_FIN C < PTD_CRS D &kp V &kp K < PTD_CRS H &cmqus &dtsmi < FUN TAB + &none &none &hello < FUN BSPC < NUM SPACE < NUM RET < FUN BSPC &encoder &none &none + &none &none &none + >; + sensor-bindings = <&inc_dec_kp UP DOWN &inc_dec_kp UP DOWN>; + slider-bindings = <&slv &slv>; + trackball-bindings = <&tmv>; + }; + + number_layer { + label = "NUM"; + bindings = < + &bt BT_NXT &mkp MB4 &kp UP &mkp MB5 &spc1 &kp PLUS &kp N7 &kp N8 &kp N9 &kp MINUS + &bt BT_PRV &kp LEFT &kp DOWN &kp RIGHT &spc2 &kp ASTRK &kp N4 &kp N5 &kp N6 &kp FSLH + &bt BT_CLR &prv_tab &none &nxt_tab &spc3 &kp N0 &kp N1 &kp N2 &kp N3 &kp DOT + &none &none &hello &spc4 &kp HOME &kp END &kp N0 &encoder &none &none + &none &none &none + >; + sensor-bindings = <&inc_dec_kp UP DOWN &inc_dec_kp UP DOWN>; + slider-bindings = <&slv &skp2 LC(MINUS) LC(PLUS)>; + trackball-bindings = <&tsl>; + }; + + symbol_layer { + label = "SYM"; + bindings = < + &none &kp TILDE &kp LT &kp GT &kp PRCNT &kp AMPS &kp CARET &kp LBRC &kp RBRC &none + &kp GRAVE &kp EXCL &kp MINUS &kp PLUS &kp EQUAL &kp PIPE &kp COLON &kp LPAR &kp RPAR &kp AT + &none &none &kp SLASH &kp STAR &kp BSLH &kp HASH &kp DLLR &kp LBKT &kp RBKT &none + &none &none &hello &none &none &none &none &encoder &none &none + &none &none &none + >; + sensor-bindings = <&inc_dec_kp UP DOWN &inc_dec_kp UP DOWN>; + slider-bindings = <&slv &skp2 LC(LS(TAB)) LC(TAB)>; + trackball-bindings = <&tkp BSPC DELETE LC(MINUS) LC(PLUS)>; + }; + + function_layer { + label = "FUN"; + bindings = < + &none &kp F1 &kp F2 &kp F3 &none &none &kp F4 &kp F5 &kp F6 &none + &none &kp F7 &kp F8 &kp F9 &none &none &kp F10 &kp F11 &kp F12 &none + &none &none &none &none &none &none &none &none &none &none + &none &none &none &none &none &none &none &none &none &none + &none &none &none + >; + sensor-bindings = <&inc_dec_kp UP DOWN &inc_dec_kp UP DOWN>; + slider-bindings = <&slv &slv>; + trackball-bindings = <&tkp_fast RIGHT LEFT DOWN UP>; + }; + + ptd_coarse_layer { + label = "PTD_COARSE"; + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans + >; + sensor-bindings = <&inc_dec_kp UP DOWN &inc_dec_kp UP DOWN>; + slider-bindings = <&slv &slv>; + trackball-bindings = <&tmv_coarse>; + }; + + ptd_navigation_layer { + label = "PTD_NAVIGATION"; + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans + >; + sensor-bindings = <&inc_dec_kp UP DOWN &inc_dec_kp UP DOWN>; + slider-bindings = <&slv &slv>; + trackball-bindings = <&tkp LC(TAB) LC(LS(TAB)) LG(PG_UP) LG(PG_DN)>; + }; + + ptd_horizontal_layer { + label = "PTD_HORIZONTAL"; + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans + >; + sensor-bindings = <&inc_dec_kp UP DOWN &inc_dec_kp UP DOWN>; + slider-bindings = <&slv &slv>; + trackball-bindings = <&tmv_x>; + }; + + ptd_vertical_layer { + label = "PTD_VERTICAL"; + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans + >; + sensor-bindings = <&inc_dec_kp UP DOWN &inc_dec_kp UP DOWN>; + slider-bindings = <&slv &slv>; + trackball-bindings = <&tmv_y>; + }; + + ptd_fine_layer { + label = "PTD_FINE"; + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans + >; + sensor-bindings = <&inc_dec_kp UP DOWN &inc_dec_kp UP DOWN>; + slider-bindings = <&slv &slv>; + trackball-bindings = <&tmv_fine>; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/blade/blade_left.conf b/app/boards/shields/blade/blade_left.conf new file mode 100644 index 00000000000..32ac9b9b641 --- /dev/null +++ b/app/boards/shields/blade/blade_left.conf @@ -0,0 +1,79 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Set the role of the split, used in choosing the dedicated status screen +CONFIG_NRFMACRO_SHIELD_SLAVE=y + +#### Enable display #### +CONFIG_ZMK_DISPLAY=y +CONFIG_LVGL_USE_THEME_MONO=y +CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y +CONFIG_ZMK_DISPLAY_FULL_REFRESH_PERIOD=10 + +# use LCD display +# CONFIG_NRFMACRO_LCD_DISPLAY=y + +# or use EPD display +CONFIG_NRFMACRO_EPD_DISPLAY=y +CONFIG_NRFMACRO_EPD_ROTATE_180=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_BLACK=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_WHITE=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_RED=n +CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_RED=n +# custom screen or not +## uncommet following for custom screen +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM=y +CONFIG_LVGL_THEME_DEFAULT_FONT_NORMAL_MONTSERRAT_16=y +CONFIG_CUSTOM_WIDGET_BATTERY_STATUS=y +CONFIG_ZMK_WIDGET_BATTERY_STATUS=n +CONFIG_CUSTOM_WIDGET_PERIPHERAL_STATUS=y +CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS=n +CONFIG_NRFMACRO_SCREEN_MARK_LOGO=y +# use custom logo or not +# CONFIG_NRFMACRO_SCREEN_STANDARD_LOGO=y +# CONFIG_NRFMACRO_SCREEN_CUSTOM_LOGO=y + +#### Enable encoder support #### +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# # set transmission power to max +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y + +##### Slider #### +# CONFIG_CAP1203_SLIDER_MODE=y + +##### Point Devices #### +# CONFIG_ZMK_PD_WORK_QUEUE_DEDICATED=n +# CONFIG_ZMK_PD_DEDICATED_WORK_QUEUE_PRIORITY=2 +# CONFIG_ZMK_TRACKBALL_POLL_DURATION=8 + +# CONFIG_ZMK_MOUSE=y +# CONFIG_ZMK_MOUSE_TICK_DURATION=10 +# CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED=y +# CONFIG_ZMK_MOUSE_DEDICATED_THREAD_PRIORITY=1 + +# CONFIG_PMW3610=y +# CONFIG_PMW3610_CPI=3200 +# CONFIG_PMW3610_CPI_DIVIDOR=4 +# CONFIG_PMW3610_ORIENTATION_90=y +# CONFIG_PMW3610_REST1_SAMPLE_TIME_MS=100 +# CONFIG_PMW3610_REST2_SAMPLE_TIME_MS=200 +# CONFIG_PMW3610_REST3_SAMPLE_TIME_MS=300 +# CONFIG_PMW3610_RUN_DOWNSHIFT_TIME_MS=500 +# CONFIG_PMW3610_REST1_DOWNSHIFT_TIME_MS=3000 +# CONFIG_PMW3610_REST2_DOWNSHIFT_TIME_MS=30000 + +### Bluetooth ### +# CONFIG_BT_PERIPHERAL_PREF_MAX_INT=9 +# CONFIG_BT_PERIPHERAL_PREF_LATENCY=16 +# CONFIG_BT_BUF_ACL_TX_COUNT=32 +# CONFIG_BT_L2CAP_TX_BUF_COUNT=32 + +# CONFIG_ZMK_BATTERY_REPORT_INTERVAL=10 + +### logging +# CONFIG_ZMK_USB_LOGGING=y +# CONFIG_ZMK_LOG_LEVEL_INF=y +# CONFIG_BATTERY_LOG_LEVEL_DBG=y +# CONFIG_PMW3610_LOG_LEVEL_INF=y diff --git a/app/boards/shields/blade/blade_left.overlay b/app/boards/shields/blade/blade_left.overlay new file mode 100644 index 00000000000..9409287152e --- /dev/null +++ b/app/boards/shields/blade/blade_left.overlay @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "blade.dtsi" + +/* Define kscan pins */ +/ { + kscan0: kscan0 { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN0"; + + diode-direction = "col2row"; + row-gpios + = <&gpio0 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 28 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&gpio1 13 GPIO_ACTIVE_HIGH> + , <&gpio0 2 GPIO_ACTIVE_HIGH> + , <&gpio0 29 GPIO_ACTIVE_HIGH> + , <&gpio0 31 GPIO_ACTIVE_HIGH> + , <&gpio0 30 GPIO_ACTIVE_HIGH> + ; + }; +}; + +/* Voltage divider based fuel gauge */ +&chosen { + zmk,battery = &vbatt; +}; + +/* Define display */ +&chosen { + zephyr,display = &epd; +}; + +&nrfmacro_spi { + // activate this device + status = "okay"; + + compatible = "nordic,nrf-spim"; + sck-pin = <20>; + mosi-pin = <17>; + cs-gpios = <&gpio0 24 GPIO_ACTIVE_LOW>; + // not used, but required by spim binding; can be reuesd in the keymap for normal key press + miso-pin = <22>; + + + // spi-device: gooddisplay GDEW0102T4 + epd: il0323@0 { + compatible = "gooddisplay,il0323"; + reg = <0>; + label = "DISPLAY"; + spi-max-frequency = <4000000>; + + height = <128>; + width = <80>; + reset-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; + dc-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + busy-gpios = <&gpio0 9 GPIO_ACTIVE_LOW>; + pwr = [03 00 26 26]; + cdi = <0xd2>; + tcon = <0x22>; + }; +}; + +// Define encoder pins +&encoder_left { + status = "okay"; + a-gpios = <&gpio1 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&gpio1 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; +}; \ No newline at end of file diff --git a/app/boards/shields/blade/blade_right.conf b/app/boards/shields/blade/blade_right.conf new file mode 100644 index 00000000000..33b5add8f67 --- /dev/null +++ b/app/boards/shields/blade/blade_right.conf @@ -0,0 +1,81 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Set the role of the split, used in choosing the dedicated status screen +# CONFIG_NRFMACRO_SHIELD_SLAVE=y + +#### Enable display #### +CONFIG_ZMK_DISPLAY=y +CONFIG_LVGL_USE_THEME_MONO=y +CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y +CONFIG_ZMK_DISPLAY_FULL_REFRESH_PERIOD=10 + +# use LCD display +CONFIG_NRFMACRO_LCD_DISPLAY=y + +# or use EPD display +# CONFIG_NRFMACRO_EPD_DISPLAY=y +# CONFIG_NRFMACRO_EPD_ROTATE_180=y +# CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_BLACK=y +# CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_WHITE=y +# CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_RED=n +# CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_RED=n +# # custom screen or not +# ## uncommet following for custom screen +# CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM=y +# CONFIG_LVGL_THEME_DEFAULT_FONT_NORMAL_MONTSERRAT_16=y +# CONFIG_CUSTOM_WIDGET_BATTERY_STATUS=y +# CONFIG_ZMK_WIDGET_BATTERY_STATUS=n +# CONFIG_CUSTOM_WIDGET_PERIPHERAL_STATUS=y +# CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS=n +# CONFIG_NRFMACRO_SCREEN_MARK_LOGO=y +# # use custom logo or not +# # CONFIG_NRFMACRO_SCREEN_STANDARD_LOGO=y +# # CONFIG_NRFMACRO_SCREEN_CUSTOM_LOGO=y + +#### Enable encoder support #### +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# # set transmission power to max +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y + +##### Slider #### +CONFIG_CAP1203_SLIDER_MODE=y +# CONFIG_CAP1203_MIX_MODE=y + +##### Point Devices #### +# CONFIG_ZMK_PD_WORK_QUEUE_DEDICATED=n +CONFIG_ZMK_PD_DEDICATED_WORK_QUEUE_PRIORITY=2 +CONFIG_ZMK_TRACKBALL_POLL_DURATION=8 + +CONFIG_ZMK_MOUSE=y +CONFIG_ZMK_MOUSE_TICK_DURATION=10 +CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED=y +CONFIG_ZMK_MOUSE_DEDICATED_THREAD_PRIORITY=1 + +CONFIG_PMW3610=y +CONFIG_PMW3610_CPI=2000 +CONFIG_PMW3610_CPI_DIVIDOR=1 +CONFIG_PMW3610_ORIENTATION_90=y +CONFIG_PMW3610_REST1_SAMPLE_TIME_MS=100 +CONFIG_PMW3610_REST2_SAMPLE_TIME_MS=200 +CONFIG_PMW3610_REST3_SAMPLE_TIME_MS=250 +CONFIG_PMW3610_RUN_DOWNSHIFT_TIME_MS=500 +CONFIG_PMW3610_REST1_DOWNSHIFT_TIME_MS=5000 +CONFIG_PMW3610_REST2_DOWNSHIFT_TIME_MS=30000 + +### Bluetooth ### +CONFIG_BT_PERIPHERAL_PREF_MAX_INT=9 +CONFIG_BT_PERIPHERAL_PREF_LATENCY=16 +CONFIG_BT_BUF_ACL_TX_COUNT=32 +CONFIG_BT_L2CAP_TX_BUF_COUNT=32 + +# CONFIG_ZMK_BATTERY_REPORT_INTERVAL=10 + +### logging +# CONFIG_ZMK_USB_LOGGING=y +# CONFIG_ZMK_LOG_LEVEL_INF=y +# CONFIG_BATTERY_LOG_LEVEL_DBG=y +# CONFIG_PMW3610_LOG_LEVEL_INF=y + diff --git a/app/boards/shields/blade/blade_right.overlay b/app/boards/shields/blade/blade_right.overlay new file mode 100644 index 00000000000..280d2d8f95d --- /dev/null +++ b/app/boards/shields/blade/blade_right.overlay @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "blade.dtsi" + +/* overrides nrfmacro.dts defaults */ +&blue_led { + gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; +}; + +&vcc_ctrl { + control-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; +}; + +&vbatt { + status = "disabled"; +}; + +/* adjust matrix transform for pepripheral split */ +&default_transform { + col-offset = <5>; +}; + +/* Define kscan pins */ +/ { + kscan0: kscan0 { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN0"; + + diode-direction = "col2row"; + row-gpios + = <&gpio0 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&gpio0 26 GPIO_ACTIVE_HIGH> + , <&gpio0 28 GPIO_ACTIVE_HIGH> + , <&gpio1 13 GPIO_ACTIVE_HIGH> + , <&gpio0 30 GPIO_ACTIVE_HIGH> + , <&gpio0 31 GPIO_ACTIVE_HIGH> + ; + }; +}; + +&kscan { + touch_keys { + kscan = <&slider_right>; + row-offset = <4>; + }; +}; + +/* Enable the right slider and define its pins */ +&slider_right { + status = "okay"; + invert-direction; + int-gpios = <&gpio1 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; +}; + +/* Enable fuel gauge */ +&chosen { + zmk,battery = &fuel_gauge; +}; + +/* Define sda and scl pins */ +&i2c0 { + sda-pin = <8>; + scl-pin = <4>; + + /* Define the fuel gauge */ + fuel_gauge: fuel_gauge@36 { + compatible = "zmk,battery-max17048"; + label = "BATTERY_FUELGAUGE"; + reg = <0x36>; + }; +}; + +/* Define display */ +&chosen { + zephyr,display = &lcd; +}; + +&nrfmacro_spi { + // activate this device + status = "okay"; + + compatible = "nordic,nrf-spim"; + sck-pin = <32>; + mosi-pin = <22>; + cs-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; + // Unused pin, needed for SPI definition, but not used by the display driver itself. + miso-pin = <37>; // 1.05 is not broken out on the E73 + + lcd: ls0xx@0 { + compatible = "sharp,ls0xx"; + label = "DISPLAY"; + spi-max-frequency = <2000000>; + reg = <0>; + width = <160>; + height = <68>; + // extcomin-gpios = <&pro_micro 2 GPIO_ACTIVE_HIGH>; + // extcomin-frequency = <60>; + // disp-en-gpios = <&pro_micro 3 GPIO_ACTIVE_HIGH>; + }; +}; + +/* Enable spi2 bus and the trackball, and define their pins */ +&spi2 { + status = "okay"; + sck-pin = <17>; + mosi-pin = <12>; + miso-pin = <12>; // same as mosi (3-wire spi) + cs-gpios = <&gpio0 24 GPIO_ACTIVE_LOW>; +}; + +&trackball { + status = "okay"; + irq-gpios = <&gpio0 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; +}; + +/* Enable the right encoder and define its pins */ +// &right_encoder { +// status = "okay"; +// a-gpios = <&gpio1 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; +// b-gpios = <&gpio1 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; +// }; \ No newline at end of file diff --git a/app/boards/shields/corne-pro/Kconfig.defconfig b/app/boards/shields/corne-pro/Kconfig.defconfig new file mode 100644 index 00000000000..f48e921fc06 --- /dev/null +++ b/app/boards/shields/corne-pro/Kconfig.defconfig @@ -0,0 +1,33 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if CORNE_PRO_LEFT + +config ZMK_KEYBOARD_NAME + default "Corne-Pro" + +config ZMK_SPLIT_BLE_ROLE_CENTRAL + default y + +endif + +if CORNE_PRO_RIGHT +config ZMK_KEYBOARD_NAME + default "Corne-Pro-R" + +endif + +if CORNE_PRO_LEFT || CORNE_PRO_RIGHT + +config ZMK_SPLIT + default y + +config ZMK_USB + default y + +config NRFMACRO_MARKLOGO_NAME + string "Source file name of the shield mark logo" + default "cornepro-marklogo.c" + +endif + diff --git a/app/boards/shields/corne-pro/Kconfig.shield b/app/boards/shields/corne-pro/Kconfig.shield new file mode 100644 index 00000000000..46cd12da417 --- /dev/null +++ b/app/boards/shields/corne-pro/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config CORNE_PRO_LEFT + def_bool $(shields_list_contains,corne-pro_left) + +config CORNE_PRO_RIGHT + def_bool $(shields_list_contains,corne-pro_right) diff --git a/app/boards/shields/corne-pro/README.md b/app/boards/shields/corne-pro/README.md new file mode 100644 index 00000000000..b1344293d2a --- /dev/null +++ b/app/boards/shields/corne-pro/README.md @@ -0,0 +1,35 @@ +# Cradio + +Cradio is a firmware for a few 34 key keyboards, including Cradio, Hypergolic and Sweep. + +## Pin arrangement + +Some revisions of the aforementioned PCBs have slightly different pin arrangements compared to what's defined in [`cradio.dtsi`](./cradio.dtsi). If you need to swap a few keys for your particular PCB, you can easily reorder the `input-gpio` definition in your own keymap file (i.e. in `zmk-config/config/cradio.keymap`): + +```dts +/* Adjusted Cradio pin arrangement */ +/* The position of Q and B keys have been swapped */ +&kscan0 { + input-gpios + = <&pro_micro_d 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; +}; +``` + +This `&kscan0` block must be placed outside of any blocks surrounded by curly braces (`{...}`). diff --git a/app/boards/shields/corne-pro/corne-pro.dtsi b/app/boards/shields/corne-pro/corne-pro.dtsi new file mode 100644 index 00000000000..1f35a1b25fe --- /dev/null +++ b/app/boards/shields/corne-pro/corne-pro.dtsi @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + + chosen: chosen { + zmk,battery = &vbatt; + zmk,kscan = &kscan; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <4>; + + // | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | + // | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | + // | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | + // | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 | + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) + RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) + >; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + + diode-direction = "col2row"; + }; +}; + diff --git a/app/boards/shields/corne-pro/corne-pro.keymap b/app/boards/shields/corne-pro/corne-pro.keymap new file mode 100644 index 00000000000..7588af10831 --- /dev/null +++ b/app/boards/shields/corne-pro/corne-pro.keymap @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#include "../42key-common.dtsi" +// #include "../42key-common-colemak.dtsi" \ No newline at end of file diff --git a/app/boards/shields/corne-pro/corne-pro.zmk.yml b/app/boards/shields/corne-pro/corne-pro.zmk.yml new file mode 100644 index 00000000000..4e35c7c330e --- /dev/null +++ b/app/boards/shields/corne-pro/corne-pro.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: corne-pro +name: Corne-Pro +type: shield +url: https://github.com/ufan/mykeyboard +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys: +siblings: + - corne-pro_left + - corne-pro_right diff --git a/app/boards/shields/corne-pro/corne-pro_left.conf b/app/boards/shields/corne-pro/corne-pro_left.conf new file mode 100644 index 00000000000..1b2997a491e --- /dev/null +++ b/app/boards/shields/corne-pro/corne-pro_left.conf @@ -0,0 +1,37 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Set the role of the split, used in choosing the dedicated status screen +CONFIG_NRFMACRO_SHIELD_MASTER=y + +# Enable epaper display +CONFIG_ZMK_DISPLAY=y +CONFIG_NRFMACRO_EPD_DISPLAY=y +CONFIG_MYCHANGE_DISPLAY_UPDATE_MO_BEHAVIOR=n + +# diplay settings (NOTE: these configurations have to be explicitly set here in shield) +## color scheme: black/white +CONFIG_LVGL_USE_THEME_MONO=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_BLACK=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_WHITE=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_RED=n +CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_RED=n +## dedicated work queue or not +CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y + +## custom screen or not +### uncommet following for custom status screen +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM=y +CONFIG_LVGL_THEME_DEFAULT_FONT_NORMAL_MONTSERRAT_16=y +CONFIG_CUSTOM_WIDGET_BATTERY_STATUS=y +CONFIG_ZMK_WIDGET_BATTERY_STATUS=n +CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS=y +CONFIG_ZMK_WIDGET_OUTPUT_STATUS=n +CONFIG_CUSTOM_WIDGET_LAYER_STATUS=y +CONFIG_ZMK_WIDGET_LAYER_STATUS=n + +# enable usb logging +# CONFIG_ZMK_USB_LOGGING=y + +# increase transmission power to max +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y diff --git a/app/boards/shields/corne-pro/corne-pro_left.overlay b/app/boards/shields/corne-pro/corne-pro_left.overlay new file mode 100644 index 00000000000..5ab99083e00 --- /dev/null +++ b/app/boards/shields/corne-pro/corne-pro_left.overlay @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "corne-pro.dtsi" + +// setup kscan pins +&kscan { + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + ; +}; + +/* display */ +&chosen { + zephyr,display = &shield_epd; +}; + +&pro_micro_spi { + compatible = "nordic,nrf-spim"; + sck-pin = <17>; + mosi-pin = <15>; + cs-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; + // not used, but required by spim binding; can be reuesd in the keymap for normal key press + miso-pin = <22>; + + // activate this device + status = "okay"; + + // spi-device: gooddisplay GDEW0102T4 + shield_epd: il0323@0 { + compatible = "gooddisplay,il0323"; + reg = <0>; + label = "DISPLAY"; + spi-max-frequency = <4000000>; + + height = <128>; + width = <80>; + reset-gpios = <&gpio0 30 GPIO_ACTIVE_LOW>; + dc-gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; + busy-gpios = <&gpio0 31 GPIO_ACTIVE_LOW>; + pwr = [03 00 26 26]; + cdi = <0xd2>; + tcon = <0x22>; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/corne-pro/corne-pro_right.conf b/app/boards/shields/corne-pro/corne-pro_right.conf new file mode 100644 index 00000000000..377a63ca81e --- /dev/null +++ b/app/boards/shields/corne-pro/corne-pro_right.conf @@ -0,0 +1,39 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Set the role of the split, used in choosing the dedicated status screen +CONFIG_NRFMACRO_SHIELD_SLAVE=y + +# Enable epaper display +CONFIG_ZMK_DISPLAY=y +CONFIG_NRFMACRO_EPD_DISPLAY=y + +# diplay settings (NOTE: these configurations have to be explicitly set here in shield) +## color scheme: black/white +CONFIG_LVGL_USE_THEME_MONO=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_BLACK=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_WHITE=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_RED=n +CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_RED=n +## dedicated work queue or not +CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y + +# custom screen or not +## uncommet following for custom screen +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM=y +CONFIG_LVGL_THEME_DEFAULT_FONT_NORMAL_MONTSERRAT_16=y +CONFIG_CUSTOM_WIDGET_BATTERY_STATUS=y +CONFIG_ZMK_WIDGET_BATTERY_STATUS=n +CONFIG_CUSTOM_WIDGET_PERIPHERAL_STATUS=y +CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS=n +CONFIG_NRFMACRO_SCREEN_MARK_LOGO=y + +# use custom logo or not +# CONFIG_NRFMACRO_SCREEN_STANDARD_LOGO=y +# CONFIG_NRFMACRO_SCREEN_CUSTOM_LOGO=y + +# enable usb logging +# CONFIG_ZMK_USB_LOGGING=y + +# increase transmission power to max +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y \ No newline at end of file diff --git a/app/boards/shields/corne-pro/corne-pro_right.overlay b/app/boards/shields/corne-pro/corne-pro_right.overlay new file mode 100644 index 00000000000..e060feeec61 --- /dev/null +++ b/app/boards/shields/corne-pro/corne-pro_right.overlay @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "corne-pro.dtsi" + +// adjust matrix transform for pepripheral split +&default_transform { + col-offset = <6>; +}; + +// setup kscan pins +&kscan { + row-gpios + = <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; +}; + +/* display */ +&chosen { + zephyr,display = &shield_epd; +}; + +&pro_micro_spi { + compatible = "nordic,nrf-spim"; + sck-pin = <15>; + mosi-pin = <17>; + cs-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; + // not used, but required by spim binding; can be reuesd in the keymap for normal key press + miso-pin = <22>; + + // activate this device + status = "okay"; + + // spi-device: gooddisplay GDEW0102T4 + shield_epd: il0323@0 { + compatible = "gooddisplay,il0323"; + reg = <0>; + label = "DISPLAY"; + spi-max-frequency = <4000000>; + + height = <128>; + width = <80>; + reset-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + dc-gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; + busy-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>; + pwr = [03 00 26 26]; + cdi = <0xd2>; + tcon = <0x22>; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/corne_cirque/Kconfig.defconfig b/app/boards/shields/corne_cirque/Kconfig.defconfig new file mode 100644 index 00000000000..ddfd2f019f5 --- /dev/null +++ b/app/boards/shields/corne_cirque/Kconfig.defconfig @@ -0,0 +1,49 @@ +if SHIELD_CORNE_CIRQUE_RIGHT + +config ZMK_KEYBOARD_NAME + default "Corne_cirque" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_CORNE_CIRQUE_LEFT || SHIELD_CORNE_RIGHT + +config ZMK_SPLIT + default y + +config ZMK_USB + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LVGL_VDB_SIZE + default 64 + +config LVGL_DPI + default 148 + +config LVGL_BITS_PER_PIXEL + default 1 + +choice LVGL_COLOR_DEPTH + default LVGL_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/corne_cirque/Kconfig.shield b/app/boards/shields/corne_cirque/Kconfig.shield new file mode 100644 index 00000000000..e957bb0fc92 --- /dev/null +++ b/app/boards/shields/corne_cirque/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 Pete Johanson +# SPDX-License-Identifier: MIT + +config SHIELD_CORNE_CIRQUE_LEFT + def_bool $(shields_list_contains,corne_cirque_left) + +config SHIELD_CORNE_CIRQUE_RIGHT + def_bool $(shields_list_contains,corne_cirque_right) diff --git a/app/boards/shields/corne_cirque/corne_cirque.conf b/app/boards/shields/corne_cirque/corne_cirque.conf new file mode 100644 index 00000000000..1201cb11a85 --- /dev/null +++ b/app/boards/shields/corne_cirque/corne_cirque.conf @@ -0,0 +1,6 @@ +# Uncomment the following lines to enable the corne_cirque RGB Underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y + +# Uncomment the following line to enable the corne_cirque OLED Display +# CONFIG_ZMK_DISPLAY=y diff --git a/app/boards/shields/corne_cirque/corne_cirque.dtsi b/app/boards/shields/corne_cirque/corne_cirque.dtsi new file mode 100644 index 00000000000..04f9957d37e --- /dev/null +++ b/app/boards/shields/corne_cirque/corne_cirque.dtsi @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen: chosen { + zmk,kscan = &kscan; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) + RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) + >; + }; + + /* Scan matrix declaration */ + kscan: kscan { + compatible = "zmk,kscan-composite"; + label = "KSCAN"; + rows = <4>; + columns = <10>; + + /* There is a key matrix by default */ + normal_keys { + kscan = <&kscan0>; + }; + }; + + trackballs { + compatible = "zmk,keymap-trackballs"; + trackballs = <&trackpad>; + }; +}; + +&nice_nano_spi { + + /* + 1 -> sck -> P0.06 -> left 1 + 2 -> miso -> P0.17 -> left 5 + 3 -> dr -> P1.04 -> left 11 + 4 -> cs -> P0.08 -> left 2 + 5 -> mosi -> P0.20 -> left 6 + 11 -> gnd -> left 3, left 4, right 2 + 12 -> vdd -> right 4 + */ + compatible = "nordic,nrf-spim"; + status = "disabled"; + miso-pin = <17>; // P0.17 + mosi-pin = <20>; // P0.20 + sck-pin = <6>; // P0.6 + cs-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; // P1.04 + + trackpad: trackpad@0 { + compatible = "cirque,pinnacle"; + status = "disabled"; + reg = <0>; + label = "Cirque Trackpad"; + spi-max-frequency = <10000000>; + dr-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>; // P0.8 + invert-y; + sleep; + /* no-taps; */ + }; +}; + \ No newline at end of file diff --git a/app/boards/shields/corne_cirque/corne_cirque.keymap b/app/boards/shields/corne_cirque/corne_cirque.keymap new file mode 100644 index 00000000000..0fb864bf9dd --- /dev/null +++ b/app/boards/shields/corne_cirque/corne_cirque.keymap @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + #include + #include + #include + #include + #include + + / { + behaviors { + u_mt: u_mt { + compatible = "zmk,behavior-hold-tap"; + label = "U_MT"; + bindings = + <&kp>, + <&kp>; + + #binding-cells = <2>; + tapping-term-ms = <200>; + flavor = "tap-preferred"; + }; + u_lt: u_lt { + compatible = "zmk,behavior-hold-tap"; + label = "U_LT"; + bindings = + <&mo>, + <&kp>; + + #binding-cells = <2>; + tapping-term-ms = <200>; + flavor = "tap-preferred"; + }; + u_out_tog: u_out_tog { + compatible = "zmk,behavior-mod-morph"; + label = "U_OUT_TOG"; + bindings = + <&out OUT_TOG>, + <&out OUT_USB>; + + #binding-cells = <0>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + u_caps_word: u_caps_word { + compatible = "zmk,behavior-mod-morph"; + label = "U_CAPS_WORD"; + bindings = + <&caps_word>, + <&kp CAPS>; + + #binding-cells = <0>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &u_mt LGUI A &u_mt LEFT_ALT S + &u_mt LEFT_SHIFT D &u_mt LCTRL F &kp G &kp H &u_mt RCTRL J &u_mt RIGHT_SHIFT K &u_mt RIGHT_ALT L &u_mt RIGHT_GUI SEMI &u_lt 6 Z &kp X &kp C &kp V + &kp B &kp N &kp M &kp COMMA &kp DOT &u_lt 6 SLASH &u_lt 5 ESC &u_lt 2 TAB &u_lt 4 BACKSPACE &u_lt 3 ENTER &u_lt 1 SPACE + >; + trackball-bindings = <&tmv>; + }; + + layer_1 { + bindings = < + &kp NUMBER_1 &kp NUMBER_2 &kp NUMBER_3 &kp NUMBER_4 &kp NUMBER_5 &kp NUMBER_6 &kp NUMBER_7 &kp NUMBER_8 &kp NUMBER_9 &kp NUMBER_0 &u_mt LGUI NUMBER_1 &u_mt LEFT_ALT NUMBER_2 + &u_mt LEFT_SHIFT NUMBER_3 &u_mt LCTRL NUMBER_4 &kp NUMBER_5 &kp EQUAL &u_mt RCTRL NUMBER_4 &u_mt RIGHT_SHIFT NUMBER_5 &u_mt RIGHT_ALT NUMBER_6 &u_mt RIGHT_GUI NUMBER_0 &kp NUMBER_1 &kp NUMBER_2 &kp NUMBER_3 &kp NUMBER_4 + &kp NUMBER_5 &kp MINUS &kp NUMBER_1 &kp NUMBER_2 &kp NUMBER_3 &kp NUMBER_0 &kp ESC &kp TAB &kp BACKSPACE &none &none + >; + }; + + layer_2 { + bindings = < + &kp LC(Z) &kp LC(X) &kp LC(C) &kp LC(V) &kp LC(Y) &kp INS &kp HOME &kp UP &kp END &kp PG_UP &kp LGUI &kp LALT + &kp LSHFT &kp LCTRL &none &u_caps_word &kp LEFT &kp DOWN &kp RIGHT &kp PG_DN &kp LC(Z) &kp LC(X) &kp LC(C) &kp LC(V) + &kp LS(LC(Z)) &kp DEL &kp DEL &none &none &none &none &none &none &kp RET &kp SPACE + >; + }; + + layer_3 { + bindings = < + &kp LS(EXCL) &kp LS(AT) &kp LEFT_BRACE &kp RIGHT_BRACE &kp LS(TILDE) &kp LS(PIPE) &kp BSLH &kp LS(DQT) &kp LS(UNDER) &kp LS(PLUS) &kp LS(POUND) &kp LS(DLLR) + &kp LBKT &kp RIGHT_BRACKET &kp GRAVE &kp EQUAL &kp RCTRL &kp RSHFT &kp RALT &kp MINUS &kp LS(PRCNT) &kp LS(CARET) &kp LS(LPAR) &kp LS(RPAR) + &kp LS(AMPS) &kp LS(STAR) &kp LS(COLON) &kp LS(LT) &kp LS(GT) &kp LS(QMARK) &kp LS(LPAR) &kp LS(RPAR) &kp SQT &none &none + >; + }; + + layer_4 { + bindings = < + &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp LGUI &kp LALT + &kp LSHFT &kp LCTRL &kp K_APP &kp F11 &kp F12 &kp F13 &kp F14 &kp F15 &kp F16 &kp F17 &kp F18 &kp F19 + &kp F20 &kp F21 &kp F22 &kp F23 &kp F24 &kp PAUSE_BREAK &none &none &none &kp SLCK &kp PAUSE_BREAK + >; + }; + + layer_5 { + bindings = < + &kp LC(Z) &kp LC(X) &kp LC(C) &kp LC(V) &kp LC(Y) &kp LOCKING_NUM &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_MINUS &kp LGUI &kp LALT + &kp LSHFT &kp LCTRL &kp RET &kp KP_SLASH &kp KP_N4 &kp KP_N5 &kp KP_N6 &kp KP_PLUS &kp LC(Z) &kp LC(X) &kp LC(C) &kp LC(V) + &kp LS(LC(Z)) &kp KP_ASTERISK &kp N1 &kp N2 &kp N3 &kp RET &none &none &none &kp KP_N0 &kp KP_DOT + >; + }; + + layer_6 { + bindings = < + &u_out_tog &none &kp C_VOL_UP &none &none &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &out OUT_BLE &kp C_PREV + &kp C_VOL_DN &kp C_NEXT &bootloader &bootloader &bt BT_PRV &bt BT_NXT &bt BT_CLR &none &none &kp C_PP &kp C_MUTE &kp C_STOP + &none &none &none &none &none &none &none &none &none &none &none + >; + }; + }; + }; diff --git a/app/boards/shields/corne_cirque/corne_cirque.zmk.yml b/app/boards/shields/corne_cirque/corne_cirque.zmk.yml new file mode 100644 index 00000000000..136ed3e46b8 --- /dev/null +++ b/app/boards/shields/corne_cirque/corne_cirque.zmk.yml @@ -0,0 +1,14 @@ +file_format: "1" +id: corne_cirque +name: corne_cirque +type: shield +url: https://github.com/foostan/crkbd/ +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - underglow +siblings: + - corne_cirque_left + - corne_cirque_right diff --git a/app/boards/shields/corne_cirque/corne_cirque_left.conf b/app/boards/shields/corne_cirque/corne_cirque_left.conf new file mode 100644 index 00000000000..f5516fb953b --- /dev/null +++ b/app/boards/shields/corne_cirque/corne_cirque_left.conf @@ -0,0 +1,7 @@ +CONFIG_NICE_NANO_SHIELD_SLAVE=y + +# # set transmission power to max +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y + +# Uncomment the following line to enable the corne_cirque OLED Display +# CONFIG_ZMK_DISPLAY=y \ No newline at end of file diff --git a/app/boards/shields/corne_cirque/corne_cirque_left.overlay b/app/boards/shields/corne_cirque/corne_cirque_left.overlay new file mode 100644 index 00000000000..072a8a7643f --- /dev/null +++ b/app/boards/shields/corne_cirque/corne_cirque_left.overlay @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + +#include "corne_cirque.dtsi" + +/ { + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN0"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + ; + }; +}; + +&chosen { + zmk,battery = &vbatt; + zephyr,display = &oled; +}; + +&pro_micro_i2c { + status = "disabled"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + label = "DISPLAY"; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/corne_cirque/corne_cirque_right.conf b/app/boards/shields/corne_cirque/corne_cirque_right.conf new file mode 100644 index 00000000000..33c643f998b --- /dev/null +++ b/app/boards/shields/corne_cirque/corne_cirque_right.conf @@ -0,0 +1,20 @@ +CONFIG_ZMK_MOUSE=y +CONFIG_SPI=y +CONFIG_PINNACLE=y +CONFIG_PINNACLE_TRIGGER_OWN_THREAD=y + +### Bluetooth ### +CONFIG_BT_PERIPHERAL_PREF_MAX_INT=9 +CONFIG_BT_PERIPHERAL_PREF_LATENCY=16 +CONFIG_BT_BUF_ACL_TX_COUNT=32 +CONFIG_BT_L2CAP_TX_BUF_COUNT=32 + +# set transmission power to max +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y + +CONFIG_NICE_NANO_SHIELD_MASTER=y + +# Turn on logging +# CONFIG_ZMK_USB_LOGGING=y +# CONFIG_LOG=y +# CONFIG_ZMK_LOG_LEVEL_DBG=y \ No newline at end of file diff --git a/app/boards/shields/corne_cirque/corne_cirque_right.overlay b/app/boards/shields/corne_cirque/corne_cirque_right.overlay new file mode 100644 index 00000000000..9d640d4f84a --- /dev/null +++ b/app/boards/shields/corne_cirque/corne_cirque_right.overlay @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + +#include "corne_cirque.dtsi" + +&default_transform { + col-offset = <5>; +}; + +/ { + kscan0: kscan0 { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN0"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + ; + }; +}; + +&nice_nano_spi { + status = "okay"; +}; + +&trackpad { + status = "okay"; +}; + +&chosen { + zmk,battery = &vbatt; +}; diff --git a/app/boards/shields/key-common.dtsi b/app/boards/shields/key-common.dtsi new file mode 100644 index 00000000000..376e48a2849 --- /dev/null +++ b/app/boards/shields/key-common.dtsi @@ -0,0 +1,256 @@ +#define DEFAULT 0 +#define QWERT 1 +#define NUM 2 +#define SYM 3 + + // macros + macros { + ZMK_MACRO(hello, // hello world + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LS(H) &kp E &kp L &kp L &kp O> + , <&kp COMMA> + , <&kp W &kp O &kp R &kp L &kp D &kp EXCL>; + ) + + ZMK_MACRO(encoder, // for encoder switch press + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LS(I) &kp SPACE &kp A &kp M &kp SPACE &kp A &kp SPACE> + , <&kp E &kp N &kp C &kp O &kp D &kp E &kp R>; + ) + + ZMK_MACRO(spc1, // for spacemacs window nav, Alt+M+1 + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N1>; + ) + + ZMK_MACRO(spc2, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N2>; + ) + + ZMK_MACRO(spc3, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N3>; + ) + + ZMK_MACRO(spc4, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LA(M) &kp N4>; + ) + + ZMK_MACRO(nxt_tab, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LC(TAB)>; + ) + + ZMK_MACRO(prv_tab, + wait-ms = <0>; + tap-ms = <10>; + bindings = <&kp LC(LS(TAB))>; + ) + }; + + // custom shift using mod-morph + behaviors { + cmqus: comma_question { + compatible = "zmk,behavior-mod-morph"; + label = "COMMA_QUESTION"; + #binding-cells = <0>; + bindings = <&kp COMMA>, <&kp QUESTION>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + + dtsmi: dot_semi { + compatible = "zmk,behavior-mod-morph"; + label = "DOT_SEMI"; + #binding-cells = <0>; + bindings = <&kp DOT>, <&kp SEMI>; + mods = <(MOD_LSFT|MOD_RSFT)>; + masked_mods = <(MOD_LSFT|MOD_RSFT)>; // don't send shift + }; + }; + + // combos + combos { + compatible = "zmk,combos"; + // right hand + combo_esc { + timeout-ms = <50>; + key-positions = <16 17>; + bindings = <&kp ESC>; + }; + + combo_lgui { + timeout-ms = <50>; + key-positions = <5 6>; + bindings = <&kp LGUI>; + }; + + combo_fullscreen { + timeout-ms = <50>; + key-positions = <25 26>; + bindings = <&kp F11>; + }; + + combo_wkspc_up { + timeout-ms = <50>; + key-positions = <9 19>; + bindings = <&kp LC(UP)>; + }; + + combo_wkspc_down { + timeout-ms = <50>; + key-positions = <19 29>; + bindings = <&kp LC(DOWN)>; + }; + + combo_win_up { + timeout-ms = <50>; + key-positions = <7 8>; + bindings = <&kp LS(LG(UP))>; + }; + + combo_win_down { + timeout-ms = <50>; + key-positions = <27 28>; + bindings = <&kp LS(LG(DOWN))>; + }; + + combo_win_left { + timeout-ms = <50>; + key-positions = <17 18>; + bindings = <&kp LS(LG(LEFT))>; + }; + + combo_win_right { + timeout-ms = <50>; + key-positions = <9 18>; + bindings = <&kp LS(LG(RIGHT))>; + }; + + combo_rdelete { + timeout-ms = <50>; + key-positions = <15 16>; + bindings = <&kp DELETE>; + }; + + // left hand + combo_zoomin { + timeout-ms = <50>; + key-positions = <3 4>; + bindings = <&kp LC(PLUS)>; + }; + + combo_zoomout { + timeout-ms = <50>; + key-positions = <23 24>; + bindings = <&kp LC(MINUS)>; + }; + + combo_pgdn { + timeout-ms = <50>; + key-positions = <22 23>; + bindings = <&kp PG_DN>; + }; + + combo_pgup { + timeout-ms = <50>; + key-positions = <2 3>; + bindings = <&kp PG_UP>; + }; + + combo_ldelete { + timeout-ms = <50>; + key-positions = <13 14>; + bindings = <&kp DELETE>; + }; + + // symbols + combo_underscore { + timeout-ms = <50>; + key-positions = <11 12>; + bindings = <&kp UNDERSCORE>; + }; + + combo_minus { + timeout-ms = <50>; + key-positions = <12 13>; + bindings = <&kp MINUS>; + }; + + // toggles + combo_capswd { + timeout-ms = <50>; + key-positions = <2 7>; + bindings = <&caps_word>; + }; + + combo_lsym { + timeout-ms = <50>; + key-positions = <31 34>; + bindings = <&tog SYM>; + }; + + combo_lnum { + timeout-ms = <50>; + key-positions = <32 33>; + bindings = <&tog NUM>; + }; + + // output selection + // combo_outusb { + // timeout-ms = <50>; + // key-positions = <4 14>; + // bindings = <&out OUT_USB>; + // }; + + combo_outble { + timeout-ms = <50>; + key-positions = <4 14>; + bindings = <&out OUT_BLE>; + }; + + combo_outtog { + timeout-ms = <50>; + key-positions = <4 24>; + bindings = <&out OUT_TOG>; + }; + + // ble selection + combo_ble1 { + timeout-ms = <50>; + key-positions = <14 24>; + bindings = <&bt BT_SEL 0>; + }; + + combo_ble2 { + timeout-ms = <50>; + key-positions = <13 23>; + bindings = <&bt BT_SEL 1>; + }; + + combo_ble3 { + timeout-ms = <50>; + key-positions = <12 22>; + bindings = <&bt BT_SEL 2>; + }; + + combo_ble4 { + timeout-ms = <50>; + key-positions = <11 21>; + bindings = <&bt BT_SEL 3>; + }; + + combo_ble5 { + timeout-ms = <50>; + key-positions = <10 20>; + bindings = <&bt BT_SEL 4>; + }; + }; \ No newline at end of file diff --git a/app/boards/shields/sweep-pro/Kconfig.defconfig b/app/boards/shields/sweep-pro/Kconfig.defconfig new file mode 100644 index 00000000000..adf1c989fd3 --- /dev/null +++ b/app/boards/shields/sweep-pro/Kconfig.defconfig @@ -0,0 +1,32 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SWEEP_PRO_LEFT + +config ZMK_KEYBOARD_NAME + default "Sweep-Pro" + +config ZMK_SPLIT_BLE_ROLE_CENTRAL + default y + +endif + +if SWEEP_PRO_RIGHT +config ZMK_KEYBOARD_NAME + default "Sweep-Pro-R" + +endif + +if SWEEP_PRO_LEFT || SWEEP_PRO_RIGHT + +config ZMK_SPLIT + default y + +config ZMK_USB + default y + +config NRFMACRO_MARKLOGO_NAME + string "Source file name of the shield mark logo" + default "sweepro-marklogo.c" +endif + diff --git a/app/boards/shields/sweep-pro/Kconfig.shield b/app/boards/shields/sweep-pro/Kconfig.shield new file mode 100644 index 00000000000..f938fe82692 --- /dev/null +++ b/app/boards/shields/sweep-pro/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SWEEP_PRO_LEFT + def_bool $(shields_list_contains,sweep-pro_left) + +config SWEEP_PRO_RIGHT + def_bool $(shields_list_contains,sweep-pro_right) diff --git a/app/boards/shields/sweep-pro/README.md b/app/boards/shields/sweep-pro/README.md new file mode 100644 index 00000000000..b1344293d2a --- /dev/null +++ b/app/boards/shields/sweep-pro/README.md @@ -0,0 +1,35 @@ +# Cradio + +Cradio is a firmware for a few 34 key keyboards, including Cradio, Hypergolic and Sweep. + +## Pin arrangement + +Some revisions of the aforementioned PCBs have slightly different pin arrangements compared to what's defined in [`cradio.dtsi`](./cradio.dtsi). If you need to swap a few keys for your particular PCB, you can easily reorder the `input-gpio` definition in your own keymap file (i.e. in `zmk-config/config/cradio.keymap`): + +```dts +/* Adjusted Cradio pin arrangement */ +/* The position of Q and B keys have been swapped */ +&kscan0 { + input-gpios + = <&pro_micro_d 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; +}; +``` + +This `&kscan0` block must be placed outside of any blocks surrounded by curly braces (`{...}`). diff --git a/app/boards/shields/sweep-pro/sweep-pro.dtsi b/app/boards/shields/sweep-pro/sweep-pro.dtsi new file mode 100644 index 00000000000..8c5305f930c --- /dev/null +++ b/app/boards/shields/sweep-pro/sweep-pro.dtsi @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + + chosen: chosen { + zmk,battery = &vbatt; + zmk,kscan = &kscan; + zmk,matrix_transform = &default_transform; + zephyr,display = &shield_epd; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; +// | SW1 | SW2 | SW3 | SW4 | SW5 | | SW5 | SW4 | SW3 | SW2 | SW1 | +// | SW6 | SW7 | SW8 | SW9 | SW10 | | SW10 | SW9 | SW8 | SW7 | SW6 | +// | SW11 | SW12 | SW13 | SW14 | SW15 | | SW15 | SW14 | SW13 | SW12 | SW11 | +// | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) + >; + }; + + // scan matrix + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + /* encoders */ + left_encoder: encoder_left { + compatible = "alps,ec11"; + status = "disabled"; + label = "LEFT_ENCODER"; + a-gpios = <&gpio1 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&gpio1 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + resolution = <2>; + }; + + right_encoder: encoder_right { + compatible = "alps,ec11"; + status = "disabled"; + label = "RIGHT_ENCODER"; + a-gpios = <&gpio1 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&gpio1 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + resolution = <2>; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + }; +}; + +/* display */ +&pro_micro_spi { +// &spi2 { + compatible = "nordic,nrf-spim"; + sck-pin = <20>; + mosi-pin = <17>; + cs-gpios = <&gpio0 24 GPIO_ACTIVE_LOW>; + // not used, but required by spim binding; can be reuesd in the keymap for normal key press + miso-pin = <22>; + + // activate this device + status = "okay"; + + // spi-device: gooddisplay GDEW0102T4 + shield_epd: il0323@0 { + compatible = "gooddisplay,il0323"; + reg = <0>; + label = "DISPLAY"; + spi-max-frequency = <4000000>; + + height = <128>; + width = <80>; + reset-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; + dc-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + busy-gpios = <&gpio0 9 GPIO_ACTIVE_LOW>; + pwr = [03 00 26 26]; + cdi = <0xd2>; + tcon = <0x22>; + }; +}; diff --git a/app/boards/shields/sweep-pro/sweep-pro.keymap b/app/boards/shields/sweep-pro/sweep-pro.keymap new file mode 100644 index 00000000000..76f7ba9e9d0 --- /dev/null +++ b/app/boards/shields/sweep-pro/sweep-pro.keymap @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#include "../40key-common-colemak.dtsi" \ No newline at end of file diff --git a/app/boards/shields/sweep-pro/sweep-pro.zmk.yml b/app/boards/shields/sweep-pro/sweep-pro.zmk.yml new file mode 100644 index 00000000000..b8ee11cf0ab --- /dev/null +++ b/app/boards/shields/sweep-pro/sweep-pro.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: sweep-pro +name: Sweep-Pro +type: shield +url: https://github.com/ufan/mykeyboard +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys: +siblings: + - sweep-pro_left + - sweep-pro_right diff --git a/app/boards/shields/sweep-pro/sweep-pro_left.conf b/app/boards/shields/sweep-pro/sweep-pro_left.conf new file mode 100644 index 00000000000..015059a2a62 --- /dev/null +++ b/app/boards/shields/sweep-pro/sweep-pro_left.conf @@ -0,0 +1,39 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Set the role of the split, used in choosing the dedicated status screen +CONFIG_NRFMACRO_SHIELD_MASTER=y + +# Enable epaper display +CONFIG_ZMK_DISPLAY=y +CONFIG_NRFMACRO_EPD_DISPLAY=y +CONFIG_NRFMACRO_EPD_ROTATE_180=y +CONFIG_MYCHANGE_DISPLAY_UPDATE_MO_BEHAVIOR=n + +# diplay settings (NOTE: these configurations have to be explicitly set here in shield) +## color scheme: black/white +CONFIG_LVGL_USE_THEME_MONO=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_BLACK=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_WHITE=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_RED=n +CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_RED=n +## dedicated work queue or not +CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y + +## custom screen or not +### uncommet following for custom status screen +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM=y +CONFIG_LVGL_THEME_DEFAULT_FONT_NORMAL_MONTSERRAT_16=y +CONFIG_CUSTOM_WIDGET_BATTERY_STATUS=y +CONFIG_ZMK_WIDGET_BATTERY_STATUS=n +CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS=y +CONFIG_ZMK_WIDGET_OUTPUT_STATUS=n +CONFIG_CUSTOM_WIDGET_LAYER_STATUS=y +CONFIG_ZMK_WIDGET_LAYER_STATUS=n + +# Enable encoder support +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# set transmission power to max +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y \ No newline at end of file diff --git a/app/boards/shields/sweep-pro/sweep-pro_left.overlay b/app/boards/shields/sweep-pro/sweep-pro_left.overlay new file mode 100644 index 00000000000..b99c6d75bcc --- /dev/null +++ b/app/boards/shields/sweep-pro/sweep-pro_left.overlay @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "sweep-pro.dtsi" + +// setup display +// &chosen { +// zephyr,display = &epd; +// }; + +// &nrfmacro_spi { +// status = "okay"; +// }; + +// setup kscan pins +&kscan { + col-gpios + = <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; +}; + +// enable left encoder +&left_encoder { + status = "okay"; +}; \ No newline at end of file diff --git a/app/boards/shields/sweep-pro/sweep-pro_right.conf b/app/boards/shields/sweep-pro/sweep-pro_right.conf new file mode 100644 index 00000000000..6ff996336e7 --- /dev/null +++ b/app/boards/shields/sweep-pro/sweep-pro_right.conf @@ -0,0 +1,41 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Set the role of the split, used in choosing the dedicated status screen +CONFIG_NRFMACRO_SHIELD_SLAVE=y + +# Enable epaper display +CONFIG_ZMK_DISPLAY=y +CONFIG_NRFMACRO_EPD_DISPLAY=y +CONFIG_NRFMACRO_EPD_ROTATE_180=y + +# diplay settings (NOTE: these configurations have to be explicitly set here in shield) +## color scheme: black/white +CONFIG_LVGL_USE_THEME_MONO=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_BLACK=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_WHITE=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_RED=n +CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_RED=n +## dedicated work queue or not +CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y + +# custom screen or not +## uncommet following for custom screen +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM=y +CONFIG_LVGL_THEME_DEFAULT_FONT_NORMAL_MONTSERRAT_16=y +CONFIG_CUSTOM_WIDGET_BATTERY_STATUS=y +CONFIG_ZMK_WIDGET_BATTERY_STATUS=n +CONFIG_CUSTOM_WIDGET_PERIPHERAL_STATUS=y +CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS=n +CONFIG_NRFMACRO_SCREEN_MARK_LOGO=y + +# use custom logo or not +# CONFIG_NRFMACRO_SCREEN_STANDARD_LOGO=y +# CONFIG_NRFMACRO_SCREEN_CUSTOM_LOGO=y + +# Enable encoder support +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# set transmission power to max +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y \ No newline at end of file diff --git a/app/boards/shields/sweep-pro/sweep-pro_right.overlay b/app/boards/shields/sweep-pro/sweep-pro_right.overlay new file mode 100644 index 00000000000..2ae3d83d8a8 --- /dev/null +++ b/app/boards/shields/sweep-pro/sweep-pro_right.overlay @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "sweep-pro.dtsi" + +// adjust matrix transform for pepripheral split +&default_transform { + col-offset = <5>; +}; + +// setup kscan pins +&kscan { + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + ; +}; + +// enable right encoder +&right_encoder { + status = "okay"; +}; \ No newline at end of file diff --git a/app/boards/shields/sweepro-ce/Kconfig.defconfig b/app/boards/shields/sweepro-ce/Kconfig.defconfig new file mode 100644 index 00000000000..79f7f31da1f --- /dev/null +++ b/app/boards/shields/sweepro-ce/Kconfig.defconfig @@ -0,0 +1,32 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SWEEPRO_CE_LEFT + +config ZMK_KEYBOARD_NAME + default "SweepPro-CE" + +config ZMK_SPLIT_BLE_ROLE_CENTRAL + default y + +endif + +if SWEEPRO_CE_RIGHT +config ZMK_KEYBOARD_NAME + default "SweepPro-CE-R" + +endif + +if SWEEPRO_CE_LEFT || SWEEPRO_CE_RIGHT + +config ZMK_SPLIT + default y + +config ZMK_USB + default y + +config NRFMACRO_MARKLOGO_NAME + string "Source file name of the shield mark logo" + default "sweepro-marklogo.c" +endif + diff --git a/app/boards/shields/sweepro-ce/Kconfig.shield b/app/boards/shields/sweepro-ce/Kconfig.shield new file mode 100644 index 00000000000..457e8f7cd42 --- /dev/null +++ b/app/boards/shields/sweepro-ce/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SWEEPRO_CE_LEFT + def_bool $(shields_list_contains,sweepro-ce_left) + +config SWEEPRO_CE_RIGHT + def_bool $(shields_list_contains,sweepro-ce_right) diff --git a/app/boards/shields/sweepro-ce/README.md b/app/boards/shields/sweepro-ce/README.md new file mode 100644 index 00000000000..b1344293d2a --- /dev/null +++ b/app/boards/shields/sweepro-ce/README.md @@ -0,0 +1,35 @@ +# Cradio + +Cradio is a firmware for a few 34 key keyboards, including Cradio, Hypergolic and Sweep. + +## Pin arrangement + +Some revisions of the aforementioned PCBs have slightly different pin arrangements compared to what's defined in [`cradio.dtsi`](./cradio.dtsi). If you need to swap a few keys for your particular PCB, you can easily reorder the `input-gpio` definition in your own keymap file (i.e. in `zmk-config/config/cradio.keymap`): + +```dts +/* Adjusted Cradio pin arrangement */ +/* The position of Q and B keys have been swapped */ +&kscan0 { + input-gpios + = <&pro_micro_d 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; +}; +``` + +This `&kscan0` block must be placed outside of any blocks surrounded by curly braces (`{...}`). diff --git a/app/boards/shields/sweepro-ce/sweepro-ce.dtsi b/app/boards/shields/sweepro-ce/sweepro-ce.dtsi new file mode 100644 index 00000000000..3f21c69899c --- /dev/null +++ b/app/boards/shields/sweepro-ce/sweepro-ce.dtsi @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + + chosen: chosen { + zmk,battery = &vbatt; + zmk,kscan = &kscan; + zmk,matrix_transform = &default_transform; + zephyr,display = &shield_epd; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; +// | SW1 | SW2 | SW3 | SW4 | SW5 | | SW5 | SW4 | SW3 | SW2 | SW1 | +// | SW6 | SW7 | SW8 | SW9 | SW10 | | SW10 | SW9 | SW8 | SW7 | SW6 | +// | SW11 | SW12 | SW13 | SW14 | SW15 | | SW15 | SW14 | SW13 | SW12 | SW11 | +// | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) + RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) + >; + }; + + // use composite kscan: 1. 34 keys with key matrix; 2. 2 extra keys from encoder with direct connect + kscan: kscan { + compatible = "zmk,kscan-composite"; + label = "KSCAN"; + rows = <4>; + columns = <10>; + + normal_keys { + kscan = <&kscan_matrix>; + }; + + encoder_keys: encoder_keys { + kscan = <&kscan_direct>; + row-offset = <3>; + // column-offset = <2>; + }; + }; + + // 1. scan normal key switches + kscan_matrix: kscan_matrix { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN_MATRIX"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + // 2. scan encoder switch + kscan_direct: kscan_direct { + compatible = "zmk,kscan-gpio-direct"; + label = "KSCAN_DIRECT"; + input-gpios = <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + }; + + /* encoders */ + left_encoder: encoder_left { + compatible = "alps,ec11"; + status = "disabled"; + label = "LEFT_ENCODER"; + a-gpios = <&pro_micro 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + resolution = <2>; + }; + + right_encoder: encoder_right { + compatible = "alps,ec11"; + status = "disabled"; + label = "RIGHT_ENCODER"; + a-gpios = <&pro_micro 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + resolution = <2>; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + }; +}; + +/* display */ +&pro_micro_spi { +// &spi2 { + compatible = "nordic,nrf-spim"; + sck-pin = <17>; + mosi-pin = <15>; + cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + // not used, but required by spim binding; can be reuesd in the keymap for normal key press + miso-pin = <10>; + + // activate this device + status = "okay"; + + // spi-device: gooddisplay GDEW0102T4 + shield_epd: il0323@0 { + compatible = "gooddisplay,il0323"; + reg = <0>; + label = "DISPLAY"; + spi-max-frequency = <4000000>; + + height = <128>; + width = <80>; + reset-gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; + dc-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>; + busy-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; + pwr = [03 00 26 26]; + cdi = <0xd2>; + tcon = <0x22>; + }; +}; diff --git a/app/boards/shields/sweepro-ce/sweepro-ce.keymap b/app/boards/shields/sweepro-ce/sweepro-ce.keymap new file mode 100644 index 00000000000..f12978df75b --- /dev/null +++ b/app/boards/shields/sweepro-ce/sweepro-ce.keymap @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +// #include "../36key-common.dtsi" +#include "../36key-common-colemak.dtsi" \ No newline at end of file diff --git a/app/boards/shields/sweepro-ce/sweepro-ce.zmk.yml b/app/boards/shields/sweepro-ce/sweepro-ce.zmk.yml new file mode 100644 index 00000000000..d1ac73f01d8 --- /dev/null +++ b/app/boards/shields/sweepro-ce/sweepro-ce.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: sweepro-ce +name: SweepPro-CE +type: shield +url: https://github.com/ufan/mykeyboard +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys: +siblings: + - sweepro-ce_left + - sweepro-ce_right diff --git a/app/boards/shields/sweepro-ce/sweepro-ce_left.conf b/app/boards/shields/sweepro-ce/sweepro-ce_left.conf new file mode 100644 index 00000000000..015059a2a62 --- /dev/null +++ b/app/boards/shields/sweepro-ce/sweepro-ce_left.conf @@ -0,0 +1,39 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Set the role of the split, used in choosing the dedicated status screen +CONFIG_NRFMACRO_SHIELD_MASTER=y + +# Enable epaper display +CONFIG_ZMK_DISPLAY=y +CONFIG_NRFMACRO_EPD_DISPLAY=y +CONFIG_NRFMACRO_EPD_ROTATE_180=y +CONFIG_MYCHANGE_DISPLAY_UPDATE_MO_BEHAVIOR=n + +# diplay settings (NOTE: these configurations have to be explicitly set here in shield) +## color scheme: black/white +CONFIG_LVGL_USE_THEME_MONO=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_BLACK=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_WHITE=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_RED=n +CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_RED=n +## dedicated work queue or not +CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y + +## custom screen or not +### uncommet following for custom status screen +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM=y +CONFIG_LVGL_THEME_DEFAULT_FONT_NORMAL_MONTSERRAT_16=y +CONFIG_CUSTOM_WIDGET_BATTERY_STATUS=y +CONFIG_ZMK_WIDGET_BATTERY_STATUS=n +CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS=y +CONFIG_ZMK_WIDGET_OUTPUT_STATUS=n +CONFIG_CUSTOM_WIDGET_LAYER_STATUS=y +CONFIG_ZMK_WIDGET_LAYER_STATUS=n + +# Enable encoder support +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# set transmission power to max +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y \ No newline at end of file diff --git a/app/boards/shields/sweepro-ce/sweepro-ce_left.overlay b/app/boards/shields/sweepro-ce/sweepro-ce_left.overlay new file mode 100644 index 00000000000..99a51177ac5 --- /dev/null +++ b/app/boards/shields/sweepro-ce/sweepro-ce_left.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "sweepro-ce.dtsi" + +// setup display +// &chosen { +// zephyr,display = &epd; +// }; + +// &nrfmacro_spi { +// status = "okay"; +// }; + +// setup kscan pins +&kscan_matrix { + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + ; +}; + +&encoder_keys { + column-offset = <2>; +}; + +// enable left encoder +&left_encoder { + status = "okay"; +}; \ No newline at end of file diff --git a/app/boards/shields/sweepro-ce/sweepro-ce_right.conf b/app/boards/shields/sweepro-ce/sweepro-ce_right.conf new file mode 100644 index 00000000000..e3d13aca048 --- /dev/null +++ b/app/boards/shields/sweepro-ce/sweepro-ce_right.conf @@ -0,0 +1,42 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Set the role of the split, used in choosing the dedicated status screen +CONFIG_NRFMACRO_SHIELD_SLAVE=y + +# Enable epaper display +CONFIG_ZMK_DISPLAY=y +CONFIG_NRFMACRO_EPD_DISPLAY=y +CONFIG_NRFMACRO_EPD_ROTATE_180=y + +# diplay settings (NOTE: these configurations have to be explicitly set here in shield) +## color scheme: black/white +CONFIG_LVGL_USE_THEME_MONO=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_BLACK=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_WHITE=y +CONFIG_LVGL_THEME_DEFAULT_COLOR_PRIMARY_RED=n +CONFIG_LVGL_THEME_DEFAULT_COLOR_SECONDARY_RED=n +## dedicated work queue or not +CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y + +# custom screen or not +## uncommet following for custom screen +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM=y +CONFIG_LVGL_THEME_DEFAULT_FONT_SMALL_MONTSERRAT_12=y +CONFIG_LVGL_THEME_DEFAULT_FONT_NORMAL_MONTSERRAT_16=y +CONFIG_CUSTOM_WIDGET_BATTERY_STATUS=y +CONFIG_ZMK_WIDGET_BATTERY_STATUS=n +CONFIG_CUSTOM_WIDGET_PERIPHERAL_STATUS=y +CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS=n +CONFIG_NRFMACRO_SCREEN_MARK_LOGO=y + +# use custom logo or not +# CONFIG_NRFMACRO_SCREEN_STANDARD_LOGO=y +# CONFIG_NRFMACRO_SCREEN_CUSTOM_LOGO=y + +# Enable encoder support +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# set transmission power to max +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y \ No newline at end of file diff --git a/app/boards/shields/sweepro-ce/sweepro-ce_right.overlay b/app/boards/shields/sweepro-ce/sweepro-ce_right.overlay new file mode 100644 index 00000000000..4252c2c0b40 --- /dev/null +++ b/app/boards/shields/sweepro-ce/sweepro-ce_right.overlay @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "sweepro-ce.dtsi" + +// adjust matrix transform for pepripheral split +&default_transform { + col-offset = <5>; +}; + +// setup kscan pins +&kscan_matrix { + col-gpios + = <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; +}; + +&encoder_keys { + column-offset = <2>; +}; + + +// enable right encoder +&right_encoder { + status = "okay"; +}; \ No newline at end of file diff --git a/app/boards/shields/tracktyl/Kconfig.defconfig b/app/boards/shields/tracktyl/Kconfig.defconfig new file mode 100644 index 00000000000..e6e122c54f1 --- /dev/null +++ b/app/boards/shields/tracktyl/Kconfig.defconfig @@ -0,0 +1,25 @@ +if SHIELD_TRACKTYL_RIGHT + + config ZMK_KEYBOARD_NAME + default "Tracktyl" + + config ZMK_SPLIT_BLE_ROLE_CENTRAL + default y + +endif + +if SHIELD_TRACKTYL_LEFT + + config ZMK_KEYBOARD_NAME + default "Tracktyl_left" +endif + +if SHIELD_TRACKTYL_LEFT || SHIELD_TRACKTYL_RIGHT + + config ZMK_SPLIT + default y + + config ZMK_USB + default y + +endif diff --git a/app/boards/shields/tracktyl/Kconfig.shield b/app/boards/shields/tracktyl/Kconfig.shield new file mode 100644 index 00000000000..42f86ffb065 --- /dev/null +++ b/app/boards/shields/tracktyl/Kconfig.shield @@ -0,0 +1,5 @@ +config SHIELD_TRACKTYL_LEFT + def_bool $(shields_list_contains,tracktyl_left) + +config SHIELD_TRACKTYL_RIGHT + def_bool $(shields_list_contains,tracktyl_right) diff --git a/app/boards/shields/tracktyl/tracktyl.dtsi b/app/boards/shields/tracktyl/tracktyl.dtsi new file mode 100644 index 00000000000..3a2e7260ee5 --- /dev/null +++ b/app/boards/shields/tracktyl/tracktyl.dtsi @@ -0,0 +1,88 @@ +#include + +/ { + chosen: chosen { + zmk,kscan = &kscan; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) + RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) + >; + }; + + /* Scan matrix declaration */ + kscan: kscan { + compatible = "zmk,kscan-composite"; + label = "KSCAN"; + rows = <5>; + columns = <10>; + + /* There is a key matrix by default */ + normal_keys { + kscan = <&kscan0>; + }; + }; + +/* Configure trackballs (either split can have the trackball) */ + trackballs { + compatible = "zmk,keymap-trackballs"; + trackballs = <&trackball>; + }; + +/* Configure encoders (both splits can have a encoder) */ + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&encoder_left &encoder_right>; + }; + + // define the two encoders + encoder_left: encoder_left { + compatible = "alps,ec11"; + status = "disabled"; + label = "LEFT_ENCODER"; + resolution = <2>; + }; + + encoder_right: encoder_right { + compatible = "alps,ec11"; + status = "disabled"; + label = "RIGHT_ENCODER"; + resolution = <2>; + }; +}; + +&nice_nano_spi { + /* + sck -> P0.22 -> left 7 + miso -> P0.17 -> left 5 + cs -> P0.24 -> left 8 + irq -> P1.0 -> left 9 + mosi -> P0.20 -> left 6 + gnd -> left 3, left 4, right 2 + vdd -> right 4 + */ + compatible = "nordic,nrf-spim"; + status = "disabled"; + miso-pin = <17>; // P0.17 + mosi-pin = <20>; // P0.20 + sck-pin = <22>; // P0.22 + cs-gpios = <&gpio0 24 GPIO_ACTIVE_LOW>; // P0.24 + + trackball: trackball@0 { + status = "disabled"; + compatible = "pixart,pmw3360"; + reg = <0>; + label = "Pixart PMW3360"; + irq-gpios = <&gpio1 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + spi-max-frequency = <2000000>; + scroll-layer = <1>; + }; +}; diff --git a/app/boards/shields/tracktyl/tracktyl.keymap b/app/boards/shields/tracktyl/tracktyl.keymap new file mode 100644 index 00000000000..0e52e83971f --- /dev/null +++ b/app/boards/shields/tracktyl/tracktyl.keymap @@ -0,0 +1,158 @@ +#include +#include +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + + combo_mb_lclick { + timeout-ms = <50>; + key-positions = <12 13>; + bindings = <&mkp LCLK>; + }; + + combo_mb_rclick { + timeout-ms = <50>; + key-positions = <22 23>; + bindings = <&mkp RCLK>; + }; + + combo_mb_mclick { + timeout-ms = <50>; + key-positions = <2 3>; + bindings = <&mkp MCLK>; + }; + }; + + behaviors { + u_mt: u_mt { + compatible = "zmk,behavior-hold-tap"; + label = "U_MT"; + bindings = + <&kp>, + <&kp>; + + #binding-cells = <2>; + tapping-term-ms = <200>; + flavor = "tap-preferred"; + }; + u_lt: u_lt { + compatible = "zmk,behavior-hold-tap"; + label = "U_LT"; + bindings = + <&mo>, + <&kp>; + + #binding-cells = <2>; + tapping-term-ms = <200>; + flavor = "tap-preferred"; + }; + u_out_tog: u_out_tog { + compatible = "zmk,behavior-mod-morph"; + label = "U_OUT_TOG"; + bindings = + <&out OUT_TOG>, + <&out OUT_USB>; + + #binding-cells = <0>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + u_caps_word: u_caps_word { + compatible = "zmk,behavior-mod-morph"; + label = "U_CAPS_WORD"; + bindings = + <&caps_word>, + <&kp CAPS>; + + #binding-cells = <0>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P +&u_mt LGUI A &u_mt LEFT_ALT S &u_mt LEFT_SHIFT D &u_mt LCTRL F &kp G &kp H &u_mt RCTRL J &u_mt RIGHT_SHIFT K &u_mt RIGHT_ALT L &u_mt RIGHT_GUI SEMI +&u_lt 7 Z &kp X &kp C &u_lt 6 V &kp B &u_lt 6 N &kp M &kp COMMA &kp DOT &u_lt 7 SLASH + &u_lt 5 ESC &u_lt 2 TAB &u_lt 4 BACKSPACE &u_lt 3 ENTER &u_lt 1 SPACE + >; + trackball-bindings = <&tmv>; + }; + + layer_num { + bindings = < + &kp NUMBER_1 &kp NUMBER_2 &kp NUMBER_3 &kp NUMBER_4 &kp NUMBER_5 &kp NUMBER_6 &kp NUMBER_7 &kp NUMBER_8 &kp NUMBER_9 &kp NUMBER_0 +&u_mt LGUI NUMBER_1 &u_mt LEFT_ALT NUMBER_2 &u_mt LEFT_SHIFT NUMBER_3 &u_mt LCTRL NUMBER_4 &kp NUMBER_5 &kp EQUAL &u_mt RCTRL NUMBER_4 &u_mt RIGHT_SHIFT NUMBER_5 &u_mt RIGHT_ALT NUMBER_6 &u_mt RIGHT_GUI NUMBER_0 + &kp NUMBER_1 &kp NUMBER_2 &kp NUMBER_3 &kp NUMBER_4 &kp NUMBER_5 &kp MINUS &kp NUMBER_1 &kp NUMBER_2 &kp NUMBER_3 &kp NUMBER_0 + &kp ESC &kp TAB &kp BACKSPACE &none &none + >; + trackball-bindings = <&tkp LC(TAB) LC(LS(TAB)) LG(PG_UP) LG(PG_DN)>; + }; + + layer_nav { + bindings = < +&kp LC(Z) &kp LC(X) &kp LC(C) &kp LC(V) &kp LC(Y) &kp INS &kp HOME &kp UP &kp END &kp PG_UP +&kp LGUI &kp LALT &kp LSHFT &kp LCTRL &mwh SCROLL_UP &u_caps_word &kp LEFT &kp DOWN &kp RIGHT &kp PG_DN +&kp LC(Z) &mkp RCLK &mkp MCLK &mkp LCLK &mwh SCROLL_DOWN &kp DEL &mkp LCLK &mkp MCLK &mkp RCLK &kp DEL + &none &none &none &kp RET &kp SPACE + >; + trackball-bindings = <&tmv>; + }; + + layer_symb { + bindings = < + &kp LS(EXCL) &kp LS(AT) &kp LEFT_BRACE &kp RIGHT_BRACE &kp LS(TILDE) &kp LS(PIPE) &kp BSLH &kp LS(DQT) &kp LS(UNDER) &kp LS(PLUS) +&kp LS(POUND) &kp LS(DLLR) &kp LBKT &kp RIGHT_BRACKET &kp GRAVE &kp EQUAL &kp RCTRL &kp RSHFT &kp RALT &kp MINUS +&kp LS(PRCNT) &kp LS(CARET) &kp LS(LPAR) &kp LS(RPAR) &kp LS(AMPS) &kp LS(STAR) &kp LS(COLON) &kp LS(LT) &kp LS(GT) &kp LS(QMARK) + &kp LS(LPAR) &kp LS(RPAR) &kp SQT &none &none + >; + trackball-bindings = <&tkp BSPC DELETE LC(MINUS) LC(PLUS)>; + }; + + layer_fn { + bindings = < + &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 +&kp LGUI &kp LALT &kp LSHFT &kp LCTRL &kp K_APP &kp F11 &kp F12 &kp F13 &kp F14 &kp F15 + &kp F16 &kp F17 &kp F18 &kp F19 &kp F20 &kp F21 &kp F22 &kp F23 &kp F24 &kp PAUSE_BREAK + &none &none &none &kp SLCK &kp PAUSE_BREAK + >; + trackball-bindings = <&tkp_fast RIGHT LEFT DOWN UP>; + }; + + layer_pad { + bindings = < +&kp LC(Z) &kp LC(X) &kp LC(C) &kp LC(V) &kp LC(Y) &kp LOCKING_NUM &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_MINUS + &kp LGUI &kp LALT &kp LSHFT &kp LCTRL &kp RET &kp KP_SLASH &kp KP_N4 &kp KP_N5 &kp KP_N6 &kp KP_PLUS +&kp LC(Z) &kp LC(X) &kp LC(C) &kp LC(V) &kp LS(LC(Z)) &kp KP_ASTERISK &kp N1 &kp N2 &kp N3 &kp RET + &none &none &none &kp KP_N0 &kp KP_DOT + >; + trackball-bindings = <&tmv_fine>; + }; + + layer_scroll { + bindings = < +&kp LC(Z) &kp LC(X) &kp LC(C) &kp LC(V) &kp LC(Y) &kp INS &kp HOME &kp UP &kp END &kp PG_UP +&kp LGUI &kp LALT &kp LSHFT &kp LCTRL &mwh SCROLL_UP &u_caps_word &kp LEFT &kp DOWN &kp RIGHT &kp PG_DN +&none &none &none &none &mwh SCROLL_DOWN &none &mkp LCLK &mkp MCLK &mkp RCLK &kp DEL + &none &none &none &kp RET &kp SPACE + >; + trackball-bindings = <&tsl>; + }; + + layer_media { + bindings = < +&u_out_tog &none &kp C_VOL_UP &none &none &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 +&out OUT_BLE &kp C_PREV &kp C_VOL_DN &kp C_NEXT &bootloader &bootloader &bt BT_PRV &bt BT_NXT &bt BT_CLR &none +&none &kp C_PP &kp C_MUTE &kp C_STOP &none &none &none &none &none &none + &none &none &none &none &none + >; + trackball-bindings = <&tmv>; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/tracktyl/tracktyl_left.conf b/app/boards/shields/tracktyl/tracktyl_left.conf new file mode 100644 index 00000000000..9ea8adafe68 --- /dev/null +++ b/app/boards/shields/tracktyl/tracktyl_left.conf @@ -0,0 +1,6 @@ +#### Enable encoder support #### +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y +CONFIG_NICE_NANO_SHIELD_SLAVE=y + +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y \ No newline at end of file diff --git a/app/boards/shields/tracktyl/tracktyl_left.overlay b/app/boards/shields/tracktyl/tracktyl_left.overlay new file mode 100644 index 00000000000..aaf374fd39b --- /dev/null +++ b/app/boards/shields/tracktyl/tracktyl_left.overlay @@ -0,0 +1,39 @@ +#include "tracktyl.dtsi" // Notice that the main dtsi files are included in the overlay. + +&default_transform { + col-offset = <0>; +}; + +/ { + kscan0: kscan0 { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN0"; + + diode-direction = "row2col"; // amoeba royale needs to do row2col + + row-gpios + = <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; + col-gpios + = <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; + +// Define encoder pins +&encoder_left { + status = "disabled"; // disable encoders until further hardware impl + a-gpios = <&gpio0 31 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&gpio0 29 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; +}; + +&chosen { + zmk,battery = &vbatt; +}; diff --git a/app/boards/shields/tracktyl/tracktyl_right.conf b/app/boards/shields/tracktyl/tracktyl_right.conf new file mode 100644 index 00000000000..386e73a0f36 --- /dev/null +++ b/app/boards/shields/tracktyl/tracktyl_right.conf @@ -0,0 +1,37 @@ +##### Point Devices #### +# CONFIG_ZMK_PD_WORK_QUEUE_DEDICATED=n +CONFIG_ZMK_PD_DEDICATED_WORK_QUEUE_PRIORITY=2 +CONFIG_ZMK_TRACKBALL_POLL_DURATION=8 + +CONFIG_ZMK_MOUSE=y +CONFIG_ZMK_MOUSE_TICK_DURATION=10 +CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED=y +CONFIG_ZMK_MOUSE_DEDICATED_THREAD_PRIORITY=1 + +CONFIG_PMW3360=y +CONFIG_PMW3360_CPI=2000 +CONFIG_PMW3360_CPI_DIVIDOR=1 +CONFIG_PMW3360_ORIENTATION_0=y +CONFIG_PMW3360_RUN_DOWNSHIFT_TIME_MS=500 +CONFIG_PMW3360_REST1_DOWNSHIFT_TIME_MS=5000 +CONFIG_PMW3360_REST2_DOWNSHIFT_TIME_MS=30000 + +### Bluetooth ### +CONFIG_BT_PERIPHERAL_PREF_MAX_INT=9 +CONFIG_BT_PERIPHERAL_PREF_LATENCY=16 +CONFIG_BT_BUF_ACL_TX_COUNT=32 +CONFIG_BT_L2CAP_TX_BUF_COUNT=32 + +#### Enable encoder support #### +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# set transmission power to max +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y + +CONFIG_NICE_NANO_SHIELD_MASTER=y + +# # Turn on logging +# CONFIG_ZMK_USB_LOGGING=y +# CONFIG_LOG=y +# CONFIG_ZMK_LOG_LEVEL_DBG=y \ No newline at end of file diff --git a/app/boards/shields/tracktyl/tracktyl_right.overlay b/app/boards/shields/tracktyl/tracktyl_right.overlay new file mode 100644 index 00000000000..38a428cb6ae --- /dev/null +++ b/app/boards/shields/tracktyl/tracktyl_right.overlay @@ -0,0 +1,47 @@ +#include "tracktyl.dtsi" + +&default_transform { // The matrix transform for this board is 5 columns over because the left half is 5 columns wide according to the matrix. + col-offset = <5>; +}; + +/ { + kscan0: kscan0 { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN0"; + + diode-direction = "row2col"; // amoeba royale needs to do row2col + + row-gpios + = <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; + col-gpios + = <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; + +/* Enable the right encoder and define its pins */ +&encoder_right { + status = "disabled"; // disable encoders until further hardware impl + a-gpios = <&gpio0 31 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&gpio0 29 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; +}; + +&nice_nano_spi { + status = "okay"; +}; + +&trackball { + status = "okay"; +}; + +&chosen { + zmk,battery = &vbatt; +}; \ No newline at end of file diff --git a/app/drivers/sensor/cirque_trackpad/CMakeLists.txt b/app/drivers/sensor/cirque_trackpad/CMakeLists.txt new file mode 100644 index 00000000000..fb014ffefb8 --- /dev/null +++ b/app/drivers/sensor/cirque_trackpad/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +zephyr_library() +zephyr_library_include_directories(.) +zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include) + + +zephyr_library_sources(cirque_trackpad.c) diff --git a/app/drivers/sensor/cirque_trackpad/Kconfig b/app/drivers/sensor/cirque_trackpad/Kconfig new file mode 100644 index 00000000000..16a4792482c --- /dev/null +++ b/app/drivers/sensor/cirque_trackpad/Kconfig @@ -0,0 +1,51 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +menuconfig PINNACLE + bool "PINNACLE Incremental Encoder Sensor" + depends on GPIO + depends on SPI + help + Enable driver for Cirque Pinnacle trackpads + +if PINNACLE + +choice + prompt "Trigger mode" + default PINNACLE_TRIGGER_NONE + help + Specify the type of triggering to be used by the driver. + +config PINNACLE_TRIGGER_NONE + bool "No trigger" + +config PINNACLE_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + depends on GPIO + select PINNACLE_TRIGGER + +config PINNACLE_TRIGGER_OWN_THREAD + bool "Use own thread" + depends on GPIO + select PINNACLE_TRIGGER + +endchoice + +config PINNACLE_TRIGGER + bool + +config PINNACLE_THREAD_PRIORITY + int "Thread priority" + depends on PINNACLE_TRIGGER_OWN_THREAD + default 10 + help + Priority of thread used by the driver to handle interrupts. + +config PINNACLE_THREAD_STACK_SIZE + int "Thread stack size" + depends on PINNACLE_TRIGGER_OWN_THREAD + default 1024 + help + Stack size of thread used by the driver to handle interrupts. + +endif # PINNACLE diff --git a/app/drivers/sensor/cirque_trackpad/cirque_trackpad.c b/app/drivers/sensor/cirque_trackpad/cirque_trackpad.c new file mode 100644 index 00000000000..c6c94dbeec7 --- /dev/null +++ b/app/drivers/sensor/cirque_trackpad/cirque_trackpad.c @@ -0,0 +1,269 @@ +#define DT_DRV_COMPAT cirque_pinnacle + +#include +#include +#include +#include + +#include "cirque_trackpad.h" + +LOG_MODULE_REGISTER(pinnacle, CONFIG_SENSOR_LOG_LEVEL); + +static int pinnacle_seq_read(const struct device *dev, const uint8_t start, uint8_t *buf, + const uint8_t len) { + uint8_t tx_buffer[len + 3], rx_dummy[3]; + tx_buffer[0] = PINNACLE_READ | start; + memset(&tx_buffer[1], PINNACLE_AUTOINC, len + 1); + tx_buffer[len + 2] = PINNACLE_DUMMY; + + const struct spi_buf tx_buf = { + .buf = tx_buffer, + .len = len + 3, + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1, + }; + struct spi_buf rx_buf[2] = { + { + .buf = rx_dummy, + .len = 3, + }, + { + .buf = buf, + .len = len, + }, + }; + const struct spi_buf_set rx = { + .buffers = rx_buf, + .count = 2, + }; + const struct pinnacle_data *data = dev->data; + const struct pinnacle_config *config = dev->config; + return spi_transceive(data->spi, &config->spi_config, &tx, &rx); +} + +static int pinnacle_write(const struct device *dev, const uint8_t addr, const uint8_t val) { + uint8_t tx_buffer[2] = {PINNACLE_WRITE | addr, val}; + + const struct spi_buf tx_buf = { + .buf = tx_buffer, + .len = 2, + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1, + }; + const struct pinnacle_data *data = dev->data; + const struct pinnacle_config *config = dev->config; + return spi_write(data->spi, &config->spi_config, &tx); +} + +static int pinnacle_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) { + const struct pinnacle_data *data = dev->data; + switch (chan) { + case SENSOR_CHAN_POS_DX: + val->val1 = data->dx; + val->val2 = 0; + break; + case SENSOR_CHAN_POS_DY: + val->val1 = data->dy; + val->val2 = 0; + break; + case SENSOR_CHAN_PRESS: + val->val1 = data->btn; + val->val2 = 0; + break; + default: + return -ENOTSUP; + } + return 0; +} + +static int pinnacle_sample_fetch(const struct device *dev, enum sensor_channel chan) { + uint8_t packet[3]; + int res = pinnacle_seq_read(dev, PINNACLE_2_2_PACKET0, packet, 3); + if (res < 0) { + LOG_ERR("res: %d", res); + return res; + } + struct pinnacle_data *data = dev->data; + data->btn = packet[0] & PINNACLE_PACKET0_BTN_PRIM; + data->dx = ((packet[0] & PINNACLE_PACKET0_X_SIGN) ? 0xFF00 : 0) | packet[1]; + data->dy = ((packet[0] & PINNACLE_PACKET0_Y_SIGN) ? 0xFF00 : 0) | packet[2]; + return 0; +} + +#ifdef CONFIG_PINNACLE_TRIGGER +static void set_int(const struct device *dev, const bool en) { + const struct pinnacle_config *config = dev->config; + int ret = gpio_pin_interrupt_configure(config->dr_port, config->dr_pin, + en ? GPIO_INT_LEVEL_ACTIVE : GPIO_INT_DISABLE); + /* int ret = gpio_pin_interrupt_configure(config->dr_port, config->dr_pin, en ? + * GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE); */ + if (ret < 0) { + LOG_ERR("can't set interrupt"); + } +} + +static int pinnacle_trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) { + struct pinnacle_data *data = dev->data; + + if (trig->type != SENSOR_TRIG_DATA_READY) { + return -ENOTSUP; + } + + set_int(dev, false); + + if (handler) { + data->data_ready_trigger = trig; + data->data_ready_handler = handler; + set_int(dev, true); + } + return 0; +} + +static void pinnacle_int_cb(const struct device *dev) { + struct pinnacle_data *data = dev->data; + data->data_ready_handler(dev, data->data_ready_trigger); + + // clear hardware interrupt on trackpad side + pinnacle_write(dev, PINNACLE_STATUS1, 0); + + // enable the inerrupt to the host side + set_int(dev, true); +} + +#ifdef CONFIG_PINNACLE_TRIGGER_OWN_THREAD +static void pinnacle_thread(void *arg) { + const struct device *dev = arg; + struct pinnacle_data *data = dev->data; + + while (1) { + k_sem_take(&data->gpio_sem, K_FOREVER); + pinnacle_int_cb(dev); + } +} +#elif defined(CONFIG_PINNACLE_TRIGGER_GLOBAL_THREAD) +static void pinnacle_work_cb(struct k_work *work) { + struct pinnacle_data *data = CONTAINER_OF(work, struct pinnacle_data, work); + pinnacle_int_cb(data->dev); +} +#endif + +static void pinnacle_gpio_cb(const struct device *port, struct gpio_callback *cb, uint32_t pins) { + struct pinnacle_data *data = CONTAINER_OF(cb, struct pinnacle_data, gpio_cb); + const struct device *dev = data->dev; + set_int(dev, false); // disable interrupt on mcu side + + /* pinnacle_write(dev, PINNACLE_STATUS1, 0); // clear hardware interrupt on trackpad side */ + + // dispatch data handling to work thead +#if defined(CONFIG_PINNACLE_TRIGGER_OWN_THREAD) + k_sem_give(&data->gpio_sem); +#elif defined(CONFIG_PINNACLE_TRIGGER_GLOBAL_THREAD) + k_work_submit(&data->work); +#endif +} +#endif + +#define SPI_BUS DT_BUS(DT_DRV_INST(0)) +#define SPI_REG DT_REG_ADDR(DT_DRV_INST(0)) + +static int pinnacle_init(const struct device *dev) { + struct pinnacle_data *data = dev->data; + const struct pinnacle_config *config = dev->config; + data->spi = DEVICE_DT_GET(SPI_BUS); + + // todo: wait for power-on or not + pinnacle_write(dev, PINNACLE_STATUS1, 0); // Clear CC after power-on + + // disable z-idle packets + pinnacle_write(dev, PINNACLE_Z_IDLE, 0); // No Z-Idle packets + + // set sleep-mode + if (config->sleep_en) { + pinnacle_write(dev, PINNACLE_SYS_CFG, PINNACLE_SYS_CFG_EN_SLEEP); + } + + // set tap + if (config->no_taps) { + pinnacle_write(dev, PINNACLE_FEED_CFG2, PINNACLE_FEED_CFG2_DIS_TAP); + } + + // data mode and enable feed + uint8_t feed_cfg1 = PINNACLE_FEED_CFG1_EN_FEED; + if (config->invert_x) { + feed_cfg1 |= PINNACLE_FEED_CFG1_INV_X; + } + if (config->invert_y) { + feed_cfg1 |= PINNACLE_FEED_CFG1_INV_Y; + } + if (feed_cfg1) { + pinnacle_write(dev, PINNACLE_FEED_CFG1, feed_cfg1); + } + +#ifdef CONFIG_PINNACLE_TRIGGER + data->dev = dev; + gpio_pin_configure(config->dr_port, config->dr_pin, GPIO_INPUT | config->dr_flags); + gpio_init_callback(&data->gpio_cb, pinnacle_gpio_cb, BIT(config->dr_pin)); + int ret = gpio_add_callback(config->dr_port, &data->gpio_cb); + if (ret < 0) { + LOG_ERR("Failed to set DR callback: %d", ret); + return -EIO; + } + +#if defined(CONFIG_PINNACLE_TRIGGER_OWN_THREAD) + k_sem_init(&data->gpio_sem, 0, UINT_MAX); + + k_thread_create(&data->thread, data->thread_stack, CONFIG_PINNACLE_THREAD_STACK_SIZE, + (k_thread_entry_t)pinnacle_thread, (void *)dev, 0, NULL, + K_PRIO_COOP(CONFIG_PINNACLE_THREAD_PRIORITY), 0, K_NO_WAIT); +#elif defined(CONFIG_PINNACLE_TRIGGER_GLOBAL_THREAD) + k_work_init(&data->work, pinnacle_work_cb); +#endif + pinnacle_write(dev, PINNACLE_FEED_CFG1, feed_cfg1); +#endif + return 0; +} + +static const struct sensor_driver_api pinnacle_driver_api = { +#if CONFIG_PINNACLE_TRIGGER + .trigger_set = pinnacle_trigger_set, +#endif + .sample_fetch = pinnacle_sample_fetch, + .channel_get = pinnacle_channel_get, +}; + +static struct pinnacle_data pinnacle_data; +static const struct pinnacle_config pinnacle_config = { + .spi_cs = + { + .gpio_dev = DEVICE_DT_GET(DT_GPIO_CTLR_BY_IDX(SPI_BUS, cs_gpios, SPI_REG)), + .gpio_pin = DT_GPIO_PIN_BY_IDX(SPI_BUS, cs_gpios, SPI_REG), + .delay = 0, + .gpio_dt_flags = DT_GPIO_FLAGS_BY_IDX(SPI_BUS, cs_gpios, SPI_REG), + }, + .spi_config = + { + .cs = &pinnacle_config.spi_cs, + .frequency = DT_INST_PROP(0, spi_max_frequency), + .slave = DT_INST_REG_ADDR(0), + /* .operation = (SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB), */ + .operation = (SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_MODE_CPHA), + }, + .invert_x = DT_INST_PROP(0, invert_x), + .invert_y = DT_INST_PROP(0, invert_y), + .sleep_en = DT_INST_PROP(0, sleep), + .no_taps = DT_INST_PROP(0, no_taps), +#ifdef CONFIG_PINNACLE_TRIGGER + .dr_port = DEVICE_DT_GET(DT_GPIO_CTLR(DT_DRV_INST(0), dr_gpios)), + .dr_pin = DT_INST_GPIO_PIN(0, dr_gpios), + .dr_flags = DT_INST_GPIO_FLAGS(0, dr_gpios), +#endif +}; + +DEVICE_DT_INST_DEFINE(0, pinnacle_init, NULL, &pinnacle_data, &pinnacle_config, POST_KERNEL, + CONFIG_SENSOR_INIT_PRIORITY, &pinnacle_driver_api); \ No newline at end of file diff --git a/app/drivers/sensor/cirque_trackpad/cirque_trackpad.h b/app/drivers/sensor/cirque_trackpad/cirque_trackpad.h new file mode 100644 index 00000000000..95c01a01ce1 --- /dev/null +++ b/app/drivers/sensor/cirque_trackpad/cirque_trackpad.h @@ -0,0 +1,80 @@ +#pragma once + +#include + +#define PINNACLE_READ 0xA0 +#define PINNACLE_WRITE 0x80 + +#define PINNACLE_AUTOINC 0xFC +#define PINNACLE_DUMMY 0xFB + +// Registers +#define PINNACLE_FW_ID 0x00 // ASIC ID. +#define PINNACLE_FW_VER 0x01 // Firmware Version Firmware revision number. +#define PINNACLE_STATUS1 0x02 // Contains status flags about the state of Pinnacle. +#define PINNACLE_SYS_CFG 0x03 // Contains system operation and configuration bits. +#define PINNACLE_SYS_CFG_EN_SLEEP BIT(2) +#define PINNACLE_SYS_CFG_SHUTDOWN BIT(1) +#define PINNACLE_SYS_CFG_RESET BIT(0) + +#define PINNACLE_FEED_CFG1 0x04 // Contains feed operation and configuration bits. +#define PINNACLE_FEED_CFG1_EN_FEED BIT(0) +#define PINNACLE_FEED_CFG1_ABS_MODE BIT(1) +#define PINNACLE_FEED_CFG1_DIS_FILT BIT(2) +#define PINNACLE_FEED_CFG1_DIS_X BIT(3) +#define PINNACLE_FEED_CFG1_DIS_Y BIT(4) +#define PINNACLE_FEED_CFG1_INV_X BIT(6) +#define PINNACLE_FEED_CFG1_INV_Y BIT(7) +#define PINNACLE_FEED_CFG2 0x05 // Contains feed operation and configuration bits. +#define PINNACLE_FEED_CFG2_EN_IM BIT(0) // Intellimouse +#define PINNACLE_FEED_CFG2_DIS_TAP BIT(1) // Disable all taps +#define PINNACLE_FEED_CFG2_DIS_SEC BIT(2) // Disable secondary tap +#define PINNACLE_FEED_CFG2_DIS_SCRL BIT(3) // Disable scroll +#define PINNACLE_FEED_CFG2_DIS_GE BIT(4) // Disable GlideExtend +#define PINNACLE_FEED_CFG2_SWAP_XY BIT(7) // Swap X & Y +#define PINNACLE_CAL_CFG 0x07 // Contains calibration configuration bits. +#define PINNACLE_PS2_AUX 0x08 // Contains Data register for PS/2 Aux Control. +#define PINNACLE_SAMPLE 0x09 // Sample Rate Number of samples generated per second. +#define PINNACLE_Z_IDLE 0x0A // Number of Z=0 packets sent when Z goes from >0 to 0. +#define PINNACLE_Z_SCALER 0x0B // Contains the pen Z_On threshold. +#define PINNACLE_SLEEP_INTERVAL 0x0C // Sleep Interval +#define PINNACLE_SLEEP_TIMER 0x0D // Sleep Timer +#define PINNACLE_AG_PACKET0 0x10 // trackpad Data (Pinnacle AG) +#define PINNACLE_2_2_PACKET0 0x12 // trackpad Data +#define PINNACLE_REG_COUNT 0x18 + +#define PINNACLE_PACKET0_BTN_PRIM BIT(0) // Primary button +#define PINNACLE_PACKET0_BTN_SEC BIT(1) // Secondary button +#define PINNACLE_PACKET0_BTN_AUX BIT(2) // Auxiliary (middle?) button +#define PINNACLE_PACKET0_X_SIGN BIT(4) // X delta sign +#define PINNACLE_PACKET0_Y_SIGN BIT(5) // Y delta sign + +struct pinnacle_data { + const struct device *spi; + int16_t dx, dy; + int8_t wheel; + uint8_t btn; +#ifdef CONFIG_PINNACLE_TRIGGER + const struct device *dev; + const struct sensor_trigger *data_ready_trigger; + struct gpio_callback gpio_cb; + sensor_trigger_handler_t data_ready_handler; +#if defined(CONFIG_PINNACLE_TRIGGER_OWN_THREAD) + K_THREAD_STACK_MEMBER(thread_stack, CONFIG_PINNACLE_THREAD_STACK_SIZE); + struct k_sem gpio_sem; + struct k_thread thread; +#elif defined(CONFIG_PINNACLE_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif +#endif +}; + +struct pinnacle_config { + struct spi_cs_control spi_cs; + struct spi_config spi_config; + bool invert_x, invert_y, sleep_en, no_taps; +#ifdef CONFIG_PINNACLE_TRIGGER + const struct device *dr_port; + uint8_t dr_pin, dr_flags; +#endif +}; diff --git a/app/drivers/sensor/pixart/paw3395/CMakeLists.txt b/app/drivers/sensor/pixart/paw3395/CMakeLists.txt new file mode 100644 index 00000000000..66079047d64 --- /dev/null +++ b/app/drivers/sensor/pixart/paw3395/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +zephyr_library() + +zephyr_library_sources(paw3395.c) +zephyr_library_sources(paw3395_priv.c) diff --git a/app/drivers/sensor/pixart/paw3395/Kconfig b/app/drivers/sensor/pixart/paw3395/Kconfig new file mode 100644 index 00000000000..7e20bad4375 --- /dev/null +++ b/app/drivers/sensor/pixart/paw3395/Kconfig @@ -0,0 +1,119 @@ +# Sensor data simulator +# +# Copyright (c) 2019 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +menuconfig PAW3395 + bool "PAW3395 mouse optical sensor" + select SPI + help + Enable PAW3395 mouse optical sensor. + +if PAW3395 + +config PAW3395_ENABLE_REST + bool "Enable the rest mode of PAW3395" + default y + help + The sensor downshift to rest mode with lower sampling rate + and frame rate. This saves power. + +config PAW3395_RUN_MODE + int "PAW3395's default run mode when power-on" + default 0 + help + The power-on run mode of PAW3395. + 0: high-performance mode + 1: low-performance mode + 2: office mode + 3: gaming mode + +config PAW3395_X_CPI + int "PAW3395's default CPI in x-axis" + default 1600 + range 50 9000 + help + Default X-CPI value. + +config PAW3395_Y_CPI + int "PAW3395's default CPI in y-axis" + default 1600 + range 50 9000 + help + Default Y-CPI value. + +config PAW3395_CPI_DIVIDOR + int "PAW3395's default CPI dividor" + default 4 + range 1 100 + help + Default CPI dividor value. + +config PAW3395_REST1_SAMPLE_TIME_MS + int "PAW3395's sample time in REST1 stage" + default 10 + range 1 255 + help + Default REST1 mode sample period in millisecond. + +config PAW3395_REST2_SAMPLE_TIME_MS + int "PAW3395's sample time in REST2 stage" + default 100 + range 4 1020 + help + Default REST2 mode sample period in millisecond. + +config PAW3395_REST3_SAMPLE_TIME_MS + int "PAW3395's sample time in REST3 stage" + default 504 + range 8 2040 + help + Default REST2 mode sample period in millisecond. + +config PAW3395_RUN_DOWNSHIFT_TIME_MS + int "PAW3395's default RUN mode downshift time" + default 500 + range 13 3264 + help + Default RUN mode downshift down time in milliseconds. + Time after which sensor goes from RUN to REST1 mode. + +config PAW3395_REST1_DOWNSHIFT_TIME_MS + int "PAW3395's default REST1 mode downshift time" + default 10000 + help + Default REST1 mode downshift down time in milliseconds. + Time after which sensor goes from REST1 to REST2 mode. + +config PAW3395_REST2_DOWNSHIFT_TIME_MS + int "PAW3395's default REST2 mode downshift time" + default 600000 + help + Default REST2 mode downshift down time in milliseconds. + Time after which sensor goes from REST2 to REST3 mode. + +choice + prompt "Select PAW3395 sensor orientation" + default PAW3395_ORIENTATION_0 + +config PAW3395_ORIENTATION_0 + bool "PAW3395 not rotated" + +config PAW3395_ORIENTATION_90 + bool "PAW3395 rotated 90 deg clockwise" + +config PAW3395_ORIENTATION_180 + bool "PAW3395 rotated 180 deg clockwise" + +config PAW3395_ORIENTATION_270 + bool "PAW3395 rotated 270 deg clockwise" + +endchoice + +module = PAW3395 +module-str = PAW3395 +source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config" + +endif #PAW3395 diff --git a/app/drivers/sensor/pixart/paw3395/paw3395.c b/app/drivers/sensor/pixart/paw3395/paw3395.c new file mode 100644 index 00000000000..cdcd31c542d --- /dev/null +++ b/app/drivers/sensor/pixart/paw3395/paw3395.c @@ -0,0 +1,1237 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT pixart_paw3395 + +#include +#include +#include "paw3395.h" + +#include +LOG_MODULE_REGISTER(paw3395, CONFIG_PAW3395_LOG_LEVEL); + +/* todo: add reset pin into the init sequence */ + +/* Timings (in us) used in SPI communication. Since MCU should not do other tasks during wait, k_busy_wait is used instead of k_sleep */ +// - sub-us time is rounded to us, due to the limitation of k_busy_wait, see : https://github.com/zephyrproject-rtos/zephyr/issues/6498 +#define T_NCS_SCLK 1 /* 120 ns (rounded to 1us) */ +#define T_SCLK_NCS_WR 1 /* 1 us */ +#define T_SRAD 2 /* 2 us */ +#define T_SRAD_MOTBR 2 /* same as T_SRAD */ +#define T_SRX 2 /* 2 us */ +#define T_SWX 5 /* 5 us */ +#define T_BEXIT 1 /* 500 ns (rounded to 1us)*/ + +/* Sensor registers (addresses) */ +// common registers as pmw3360 +#define PAW3395_REG_PRODUCT_ID 0x00 +#define PAW3395_REG_REVISION_ID 0x01 +#define PAW3395_REG_MOTION 0x02 +#define PAW3395_REG_DELTA_X_L 0x03 +#define PAW3395_REG_DELTA_X_H 0x04 +#define PAW3395_REG_DELTA_Y_L 0x05 +#define PAW3395_REG_DELTA_Y_H 0x06 +#define PAW3395_REG_SQUAL 0x07 +#define PAW3395_REG_RAW_DATA_SUM 0x08 +#define PAW3395_REG_MAXIMUM_RAW_DATA 0x09 +#define PAW3395_REG_MINIMUM_RAW_DATA 0x0A +#define PAW3395_REG_SHUTTER_LOWER 0x0B +#define PAW3395_REG_SHUTTER_UPPER 0x0C + +#define PAW3395_REG_OBSERVATION 0x15 +#define PAW3395_REG_MOTION_BURST 0x16 + +// power-up reset and shutdown registers +#define PAW3395_REG_POWER_UP_RESET 0x3A +#define PAW3395_REG_SHUTDOWN 0x3B + +// rest mode register +#define PAW3395_REG_PERFORMANCE 0x40 + +// resolution/cpi registers +#define PAW3395_REG_SET_RESOLUTION 0x47 +#define PAW3395_REG_RESOLUTION_X_LOW 0x48 +#define PAW3395_REG_RESOLUTION_X_HIGH 0x49 +#define PAW3395_REG_RESOLUTION_Y_LOW 0x4A +#define PAW3395_REG_RESOLUTION_Y_HIGH 0x4B + +// other registers +#define PAW3395_REG_ANGLE_SNAP 0x56 +#define PAW3395_REG_RAWDATA_OUTPUT 0x58 +#define PAW3395_REG_RAWDATA_STATUS 0x59 +#define PAW3395_REG_RIPPLE_CONTROL 0x5A +#define PAW3395_REG_AXIS_CONTROL 0x5B +#define PAW3395_REG_MOTION_CONTROL 0x5C +#define PAW3395_REG_INVERSE_PRODUCT_ID 0x5F + +// rest mode related +#define PAW3395_REG_RUN_DOWNSHIFT 0x77 +#define PAW3395_REG_REST1_PERIOD 0x78 +#define PAW3395_REG_REST1_DOWNSHIFT 0x79 +#define PAW3395_REG_REST2_PERIOD 0x7A +#define PAW3395_REG_REST2_DOWNSHIFT 0x7B +#define PAW3395_REG_REST3_PERIOD 0x7C +#define PAW3395_REG_RUN_DOWNSHIFT_MULT 0x7D +#define PAW3395_REG_REST_DOWNSHIFT_MULT 0x7E + +// the following registers need special setting procedure +#define PAW3395_REG_ANGLE_TUNE1_H 0x05 +#define PAW3395_REG_ANGLE_TUNE1_L 0x77 +#define PAW3395_REG_ANGLE_TUNE2_H 0x05 +#define PAW3395_REG_ANGLE_TUNE2_L 0x78 +#define PAW3395_REG_LIFT_CONFIG_H 0x0C +#define PAW3395_REG_LIFT_CONFIG_L 0x4E + +// the mode register is used in run mode selection +#define PAW3395_REG_RUN_MODE 0x40 + +/* Sensor identification values */ +#define PAW3395_PRODUCT_ID 0x51 + +/* Power-up register commands */ +#define PAW3395_POWERUP_CMD_RESET 0x5A + +/* Max register count readable in a single motion burst */ +#define PAW3395_MAX_BURST_SIZE 12 + +/* Register count used for reading a single motion burst */ +#define PAW3395_BURST_SIZE 6 + +/* Position of X in motion burst data */ +#define PAW3395_DX_POS 2 +#define PAW3395_DY_POS 4 + +/* Rest_En position in Performance register. */ +#define PAW3395_REST_EN_POS 7 + +/* cpi/resolution range */ +#define PAW3395_MAX_CPI 26000 +#define PAW3395_MIN_CPI 50 +#define PAW3395_SET_RESOLUTION_CMD 0x01 +#define PAW3395_RIPPLE_CONTROL_EN_POS 7 + +/* write command bit position */ +#define SPI_WRITE_BIT BIT(7) + +/* Helper macros used to convert sensor values. */ +#define PAW3395_SVALUE_TO_CPI(svalue) ((uint32_t)(svalue).val1) +#define PAW3395_SVALUE_TO_TIME(svalue) ((uint32_t)(svalue).val1) +#define PAW3395_SVALUE_TO_RUNMODE(svalue) ((uint32_t)(svalue).val1) +#define PAW3395_SVALUE_TO_BOOL(svalue) ((svalue).val1 != 0) + + +/* setting registers, defined in paw3395_priv.c */ +extern const size_t paw3395_pwrup_registers_length1; +extern const uint8_t paw3395_pwrup_registers_addr1[]; +extern const uint8_t paw3395_pwrup_registers_data1[]; +extern const size_t paw3395_pwrup_registers_length2; +extern const uint8_t paw3395_pwrup_registers_addr2[]; +extern const uint8_t paw3395_pwrup_registers_data2[]; + + +extern const size_t paw3395_mode_registers_length[]; +extern const uint8_t* paw3395_mode_registers_addr[]; +extern const uint8_t* paw3395_mode_registers_data[]; + +//////// Sensor initialization steps definition ////////// +// init is done in non-blocking manner (i.e., async), a // +// delayable work is defined for this purpose // +enum paw3395_init_step { + ASYNC_INIT_STEP_POWER_UP, // reset cs line and assert power-up reset + ASYNC_INIT_STEP_LOAD_SETTING, // load register setting + ASYNC_INIT_STEP_CONFIGURE, // set other registes like cpi and donwshift time (run, rest1, rest2) and clear motion registers + + ASYNC_INIT_STEP_COUNT // end flag +}; + +/* Timings (in ms) needed in between steps to allow each step finishes succussfully. */ +// - Since MCU is not involved in the sensor init process, i is allowed to do other tasks. +// Thus, k_sleep or delayed schedule can be used. +static const int32_t async_init_delay[ASYNC_INIT_STEP_COUNT] = { + [ASYNC_INIT_STEP_POWER_UP] = 50, // required in spec + [ASYNC_INIT_STEP_LOAD_SETTING] = 10, // 5ms required in spec, tests show >10ms + [ASYNC_INIT_STEP_CONFIGURE] = 0, +}; + +static int paw3395_async_init_power_up(const struct device *dev); +static int paw3395_async_init_load_setting(const struct device *dev); +static int paw3395_async_init_configure(const struct device *dev); + +static int (* const async_init_fn[ASYNC_INIT_STEP_COUNT])(const struct device *dev) = { + [ASYNC_INIT_STEP_POWER_UP] = paw3395_async_init_power_up, + [ASYNC_INIT_STEP_LOAD_SETTING] = paw3395_async_init_load_setting, + [ASYNC_INIT_STEP_CONFIGURE] = paw3395_async_init_configure, +}; + +//////// Function definitions ////////// + +// checked and keep +static int spi_cs_ctrl(const struct device *dev, bool enable) +{ + const struct pixart_config *config = dev->config; + int err; + + if (!enable) { + k_busy_wait(T_NCS_SCLK); + } + + err = gpio_pin_set_dt(&config->cs_gpio, (int)enable); + if (err) { + LOG_ERR("SPI CS ctrl failed"); + } + + if (enable) { + k_busy_wait(T_NCS_SCLK); + } + + return err; +} + + +// checked and keep +static int reg_read(const struct device *dev, uint8_t reg, uint8_t *buf) +{ + int err; + /* struct pixart_data *data = dev->data; */ + const struct pixart_config *config = dev->config; + + __ASSERT_NO_MSG((reg & SPI_WRITE_BIT) == 0); + + err = spi_cs_ctrl(dev, true); + if (err) { + return err; + } + + /* Write register address. */ + const struct spi_buf tx_buf = { + .buf = ®, + .len = 1 + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1 + }; + + err = spi_write_dt(&config->bus, &tx); + if (err) { + LOG_ERR("Reg read failed on SPI write"); + return err; + } + + k_busy_wait(T_SRAD); + + /* Read register value. */ + struct spi_buf rx_buf = { + .buf = buf, + .len = 1, + }; + const struct spi_buf_set rx = { + .buffers = &rx_buf, + .count = 1, + }; + + err = spi_read_dt(&config->bus, &rx); + if (err) { + LOG_ERR("Reg read failed on SPI read"); + return err; + } + + err = spi_cs_ctrl(dev, false); + if (err) { + return err; + } + + k_busy_wait(T_SRX); + + // todo: needed? + /* data->last_read_burst = false; */ + + return 0; +} + +// checked and keep +static int reg_write(const struct device *dev, uint8_t reg, uint8_t val) +{ + int err; + /* struct pixart_data *data = dev->data; */ + const struct pixart_config *config = dev->config; + + __ASSERT_NO_MSG((reg & SPI_WRITE_BIT) == 0); + + err = spi_cs_ctrl(dev, true); + if (err) { + return err; + } + + uint8_t buf[] = { + SPI_WRITE_BIT | reg, + val + }; + const struct spi_buf tx_buf = { + .buf = buf, + .len = ARRAY_SIZE(buf) + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1 + }; + + err = spi_write_dt(&config->bus, &tx); + if (err) { + LOG_ERR("Reg write failed on SPI write"); + return err; + } + + k_busy_wait(T_SCLK_NCS_WR); + + err = spi_cs_ctrl(dev, false); + if (err) { + return err; + } + + k_busy_wait(T_SWX); + + /* data->last_read_burst = false; */ + + return 0; +} + +static int motion_burst_read(const struct device *dev, uint8_t *buf, + size_t burst_size) +{ + int err; + /* struct pixart_data *data = dev->data; */ + const struct pixart_config *config = dev->config; + + __ASSERT_NO_MSG(burst_size <= PAW3395_MAX_BURST_SIZE); + + /* Write any value to motion burst register only if there have been + * other SPI transmissions with sensor since last burst read. + */ + // todo: needed or not? + /* if (!data->last_read_burst) { */ + /* err = reg_write(dev, PAW3395_REG_MOTION_BURST, 0x00); */ + /* if (err) { */ + /* return err; */ + /* } */ + /* } */ + + err = spi_cs_ctrl(dev, true); + if (err) { + return err; + } + + /* Send motion burst address */ + uint8_t reg_buf[] = { + PAW3395_REG_MOTION_BURST + }; + const struct spi_buf tx_buf = { + .buf = reg_buf, + .len = ARRAY_SIZE(reg_buf) + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1 + }; + + // todo: after sending the address, mosi should be held static until burst read is complete? how to do it in zephyr + err = spi_write_dt(&config->bus, &tx); + if (err) { + LOG_ERR("Motion burst failed on SPI write"); + return err; + } + + k_busy_wait(T_SRAD_MOTBR); + + const struct spi_buf rx_buf = { + .buf = buf, + .len = burst_size, + }; + const struct spi_buf_set rx = { + .buffers = &rx_buf, + .count = 1 + }; + + err = spi_read_dt(&config->bus, &rx); + if (err) { + LOG_ERR("Motion burst failed on SPI read"); + return err; + } + + err = spi_cs_ctrl(dev, false); + if (err) { + return err; + } + + /* Terminate burst */ + k_busy_wait(T_BEXIT); + + /* data->last_read_burst = true; */ + + return 0; +} + +/** Writing an array of registers in sequence, used in power-up register initialization and running mode switching */ +static int burst_write(const struct device *dev, const uint8_t *addr, const uint8_t *buf, size_t size) +{ + int err; + + /* Write data */ + for (size_t i = 0; i < size; i++) { + err = reg_write(dev, addr[i], buf[i]); + + if (err) { + LOG_ERR("Burst write failed on SPI write (data)"); + return err; + } + } + + /* struct pixart_data *data = dev->data; */ + /* data->last_read_burst = false; */ + + return 0; +} + +static int check_product_id(const struct device *dev) +{ + uint8_t product_id=0x01; + int err = reg_read(dev, PAW3395_REG_PRODUCT_ID, &product_id); + if (err) { + LOG_ERR("Cannot obtain product id"); + return err; + } + + if (product_id != PAW3395_PRODUCT_ID) { + LOG_ERR("Incorrect product id 0x%x (expecting 0x%x)!", product_id, PAW3395_PRODUCT_ID); + return -EIO; + } + + return 0; +} + +static int upload_pwrup_settings(const struct device *dev) +{ + LOG_INF("Upload firmware settings..."); + + // stage 1: configure the first 137 registers + LOG_INF("stag 1: upload the first 137 registers"); + int err; + err = burst_write(dev, paw3395_pwrup_registers_addr1, \ + paw3395_pwrup_registers_data1, paw3395_pwrup_registers_length1); + if(err) { + LOG_ERR("Can't setting first group of registers"); + return err; + } + + // stage 2: read register 0x6C at 1ms interval until value 0x80 is returned + // or timeout after 60 times + LOG_INF("stag 2: poll until 0x80 returned"); + uint8_t value = 0; + int count = 0; + while( count < 60 ) { + + // wait for 1ms befor read (timing accuracy 1% is required) + k_busy_wait(1000); + /* k_msleep(1); */ + + if (reg_read(dev, 0x6C, &value)) { + LOG_ERR("Failed to read register 0x6C"); + return err; + } + LOG_DBG("%d poll returns 0x%x", count+1, value); + + if( value == 0x80 ) + break; + + count++; + } + + // do some setting if 0x80 is not returned within 60 poll + if( value != 0x80 ) { + LOG_INF("value 0x80 is not returned within 60 polls, use alternative setting"); + uint8_t addr[] = {0x7F, 0x6C, 0x7F}; + uint8_t data[] = {0x14, 0x00, 0x00}; + + err = burst_write(dev, addr, data, 3); + if(err) { + LOG_ERR("Can't setting the backup registers"); + return err; + } + } + + // stage 3: configure the remaining 5 rigisters + LOG_INF("stag 3: upload the remaining 5 registers"); + err = burst_write(dev, paw3395_pwrup_registers_addr2,\ + paw3395_pwrup_registers_data2, paw3395_pwrup_registers_length2); + if(err) { + LOG_ERR("Can't setting the second group of registers"); + return err; + } + + // stage 4: check the product id + LOG_INF("stag 4: confirm the setting by checking the product id"); + err = check_product_id(dev); + if (err) { + LOG_ERR("Failed checking product id"); + return err; + } + + LOG_INF("Upload power-up register settins done"); + + return 0; +} + +static int set_run_mode(const struct device *dev, enum paw3395_run_mode run_mode) +{ + int err; + uint32_t mode_idx = (uint32_t)run_mode; + + if(mode_idx >= RUN_MODE_COUNT) { + LOG_ERR("Unknown attribute"); + return -ENOTSUP; + } + + // stage 1: write a series of registers + err = burst_write(dev, paw3395_mode_registers_addr[mode_idx],\ + paw3395_mode_registers_data[mode_idx],\ + paw3395_mode_registers_length[mode_idx]); + + // stage 2: read run_mode register and set corresponding bits + uint8_t value; + if(mode_idx == GAME_MODE) { + value = 0x83; + } + else{ + err = reg_read(dev, PAW3395_REG_RUN_MODE, &value); + if (err) { + LOG_ERR("Failed to read RUN_MODE register"); + return err; + } + } + + switch (mode_idx) { + case HP_MODE: + WRITE_BIT(value, 0, 0); + WRITE_BIT(value, 1, 0); + LOG_INF("Enable high-performance mode"); + break; + case LP_MODE: + WRITE_BIT(value, 0, 1); + WRITE_BIT(value, 1, 0); + LOG_INF("Enable low-performance mode"); + break; + case OFFICE_MODE: + WRITE_BIT(value, 0, 0); + WRITE_BIT(value, 1, 1); + LOG_INF("Enable office mode"); + break; + case GAME_MODE: + LOG_INF("Enable gaming mode"); + break; + default: + LOG_ERR("Unknown RUN mode"); + return -ENOTSUP; + } + + // stage 3: write back to run_mode register + err = reg_write(dev, PAW3395_REG_RUN_MODE, value); + if (err) { + LOG_ERR("Failed to set run mode"); + } + return err; +} + +/* set cpi (x, y seperately): axis true for x, false for y */ +static int set_cpi(const struct device *dev, uint32_t cpi, bool axis) +{ + /* Set resolution with CPI step of 50 cpi + * 0x0000: 50 cpi (minimum cpi) + * 0x0001: 100 cpi + * : + * 0x0063: 5000 cpi (default cpi) + * : + * 0x0207: 26000 cpi (maximum cpi) + */ + + if ((cpi > PAW3395_MAX_CPI) || (cpi < PAW3395_MIN_CPI)) { + LOG_ERR("CPI value %u out of range", cpi); + return -EINVAL; + } + + // Convert CPI to register value + uint16_t value = (cpi / 50) - 1; + LOG_INF("Setting %s-CPI to %u (reg value 0x%x)", axis ? "X" : "Y", cpi, value); + + // seperate the two bytes + uint8_t buf[2]; + sys_put_le16(value, buf); + + // upload the new value + int err; + if (axis) { // x-cpi + uint8_t addr[2] = {PAW3395_REG_RESOLUTION_X_LOW, PAW3395_REG_RESOLUTION_X_HIGH}; + err = burst_write(dev, addr, buf, 2); + } + else { // y-cpi + uint8_t addr[2] = {PAW3395_REG_RESOLUTION_Y_LOW, PAW3395_REG_RESOLUTION_Y_HIGH}; + err = burst_write(dev, addr, buf, 2); + } + if (err) { + LOG_ERR("Failed to upload %s-CPI", axis ? "X" : "Y"); + } + + /* set the cpi */ + if ( cpi > 9000 ) { + LOG_INF("Enable ripple control, since cpi is too large"); + + err = reg_read(dev, PAW3395_REG_RIPPLE_CONTROL, buf); + if (err) { + LOG_ERR("Failed to read RIPPLE_CONTROL register"); + return err; + } + + WRITE_BIT(buf[0], PAW3395_RIPPLE_CONTROL_EN_POS, 1); + err = reg_write(dev, PAW3395_REG_RIPPLE_CONTROL, buf[0]); + if (err) { + LOG_ERR("Failed to enable ripple control"); + } + } + + /* set the cpi */ + err = reg_write(dev, PAW3395_REG_SET_RESOLUTION, 0x01); + if (err) { + LOG_ERR("Failed to set CPI"); + } + + return err; +} + +/* Set sampling rate in each mode (in ms) */ +static int set_sample_time(const struct device *dev, uint8_t reg_addr, uint32_t sample_time) +{ + uint32_t maxtime, mintime; + switch (reg_addr) { + case PAW3395_REG_REST1_PERIOD: + mintime = 1; + maxtime = 255; + break; + case PAW3395_REG_REST2_PERIOD: + mintime = 4; + maxtime = 4*255; + break; + case PAW3395_REG_REST3_PERIOD: + mintime = 8; + maxtime = 8*255; + break; + default: + LOG_WRN("unrecognizable rest mode register"); + return -ENOTSUP; + } + + if ((sample_time > maxtime) || (sample_time < mintime)) { + LOG_WRN("Sample time %u out of range [%u, %u]", sample_time, mintime, maxtime); + return -EINVAL; + } + + uint8_t value = sample_time / mintime; + LOG_INF("Set sample time to %u ms (reg value: 0x%x)", sample_time, value); + + /* The sample time is (reg_value * mintime ) ms. 0x00 is rounded to 0x1 */ + int err = reg_write(dev, reg_addr, value); + if (err) { + LOG_ERR("Failed to change sample time"); + } + + return err; +} + + +/* time unit: ms */ +static int set_downshift_time(const struct device *dev, uint8_t reg_addr, uint32_t time) +{ + /* Set downshift time in ms: + * - Run downshift time (from Run to Rest1 mode), default: 1 s + * - Rest 1 downshift time (from Rest1 to Rest2 mode), default: ~10 s + * - Rest 2 downshift time (from Rest2 to Rest3 mode), default: ~10 min + */ + uint32_t maxtime; + uint32_t mintime; + + switch (reg_addr) { + case PAW3395_REG_RUN_DOWNSHIFT: + /* + * Run downshift time = PAW3395_REG_RUN_DOWNSHIFT * 256 * 0.05 ms + */ + maxtime = 3264; + mintime = 13; // real value is 12.8, rounded to 13 + break; + + case PAW3395_REG_REST1_DOWNSHIFT: + /* + * Rest1 downshift time = PAW3395_REG_RUN_DOWNSHIFT + * * 64 * Rest1_sample_period (default 1 ms) + */ + maxtime = 255 * 64 * CONFIG_PAW3395_REST1_SAMPLE_TIME_MS; + mintime = 64 * CONFIG_PAW3395_REST1_SAMPLE_TIME_MS; + break; + + case PAW3395_REG_REST2_DOWNSHIFT: + /* + * Rest2 downshift time = PAW3395_REG_REST2_DOWNSHIFT + * * 64 * Rest2 rate (default 100 ms) + */ + maxtime = 255 * 64 * CONFIG_PAW3395_REST2_SAMPLE_TIME_MS; + mintime = 64 * CONFIG_PAW3395_REST2_SAMPLE_TIME_MS; + break; + + default: + LOG_ERR("Not supported"); + return -ENOTSUP; + } + + if ((time > maxtime) || (time < mintime)) { + LOG_WRN("Downshift time %u out of range", time); + return -EINVAL; + } + + __ASSERT_NO_MSG((mintime > 0) && (maxtime/mintime <= UINT8_MAX)); + + /* Convert time to register value */ + uint8_t value = time / mintime; + + LOG_INF("Set downshift time to %u ms (reg value 0x%x)", time, value); + + int err = reg_write(dev, reg_addr, value); + if (err) { + LOG_ERR("Failed to change downshift time"); + } + + return err; +} + +static int set_rest_mode(const struct device *dev, bool enable) +{ + uint8_t value; + int err = reg_read(dev, PAW3395_REG_PERFORMANCE, &value); + + if (err) { + LOG_ERR("Failed to read PERFORMANCE register"); + return err; + } + + // be aware: 0 is enable, 1 is disable + WRITE_BIT(value, PAW3395_REST_EN_POS, !enable); + + LOG_INF("%sable rest modes", (enable) ? ("En") : ("Dis")); + err = reg_write(dev, PAW3395_REG_PERFORMANCE, value); + + if (err) { + LOG_ERR("Failed to set rest mode"); + } + + return err; +} + +static int paw3395_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + struct pixart_data *data = dev->data; + int err; + + if (unlikely(chan != SENSOR_CHAN_ALL)) { + return -ENOTSUP; + } + + if (unlikely(!data->ready)) { + LOG_DBG("Device is not initialized yet"); + return -EBUSY; + } + + switch ((uint32_t)attr) { + case PAW3395_ATTR_X_CPI: + err = set_cpi(dev, PAW3395_SVALUE_TO_CPI(*val), true); + break; + case PAW3395_ATTR_Y_CPI: + err = set_cpi(dev, PAW3395_SVALUE_TO_CPI(*val), false); + break; + + case PAW3395_ATTR_REST_ENABLE: + err = set_rest_mode(dev, PAW3395_SVALUE_TO_BOOL(*val)); + break; + + case PAW3395_ATTR_RUN_DOWNSHIFT_TIME: + err = set_downshift_time(dev, + PAW3395_REG_RUN_DOWNSHIFT, + PAW3395_SVALUE_TO_TIME(*val)); + break; + + case PAW3395_ATTR_REST1_DOWNSHIFT_TIME: + err = set_downshift_time(dev, + PAW3395_REG_REST1_DOWNSHIFT, + PAW3395_SVALUE_TO_TIME(*val)); + break; + + case PAW3395_ATTR_REST2_DOWNSHIFT_TIME: + err = set_downshift_time(dev, + PAW3395_REG_REST2_DOWNSHIFT, + PAW3395_SVALUE_TO_TIME(*val)); + break; + + case PAW3395_ATTR_REST1_SAMPLE_TIME: + err = set_sample_time(dev, + PAW3395_REG_REST1_PERIOD, + PAW3395_SVALUE_TO_TIME(*val)); + break; + + case PAW3395_ATTR_REST2_SAMPLE_TIME: + err = set_sample_time(dev, + PAW3395_REG_REST2_PERIOD, + PAW3395_SVALUE_TO_TIME(*val)); + break; + + case PAW3395_ATTR_REST3_SAMPLE_TIME: + err = set_sample_time(dev, + PAW3395_REG_REST3_PERIOD, + PAW3395_SVALUE_TO_TIME(*val)); + break; + + case PAW3395_ATTR_RUN_MODE: + err = set_run_mode(dev, + PAW3395_SVALUE_TO_RUNMODE(*val)); + break; + + default: + LOG_ERR("Unknown attribute"); + return -ENOTSUP; + } + + return err; +} + +static int paw3395_async_init_power_up(const struct device *dev) +{ + LOG_INF("async_init_power_up"); + + /* needed or not? Reset spi port */ + spi_cs_ctrl(dev, false); + spi_cs_ctrl(dev, true); + + /* Reset sensor */ + return reg_write(dev, PAW3395_REG_POWER_UP_RESET, PAW3395_POWERUP_CMD_RESET); +} + +static int paw3395_async_init_load_setting(const struct device *dev) +{ + LOG_INF("async_init_load_setting"); + + return upload_pwrup_settings(dev); +} + +static int paw3395_async_init_configure(const struct device *dev) +{ + LOG_INF("async_init_configure"); + + int err; + + // run mode + err = set_run_mode(dev, CONFIG_PAW3395_RUN_MODE); + + // cpi + if (!err) { + err = set_cpi(dev, CONFIG_PAW3395_X_CPI, true); + } + + if (!err) { + err = set_cpi(dev, CONFIG_PAW3395_Y_CPI, false); + } + + // sample period, which affects scaling of rest1 downshift time + if (!err) { + err = set_sample_time(dev, + PAW3395_REG_REST1_PERIOD, + CONFIG_PAW3395_REST1_SAMPLE_TIME_MS); + } + + if (!err) { + err = set_sample_time(dev, + PAW3395_REG_REST2_PERIOD, + CONFIG_PAW3395_REST2_SAMPLE_TIME_MS); + } + if (!err) { + err = set_sample_time(dev, + PAW3395_REG_REST3_PERIOD, + CONFIG_PAW3395_REST3_SAMPLE_TIME_MS); + } + + // downshift time for each rest mode + if (!err) { + err = set_downshift_time(dev, + PAW3395_REG_RUN_DOWNSHIFT, + CONFIG_PAW3395_RUN_DOWNSHIFT_TIME_MS); + } + + if (!err) { + err = set_downshift_time(dev, + PAW3395_REG_REST1_DOWNSHIFT, + CONFIG_PAW3395_REST1_DOWNSHIFT_TIME_MS); + } + + if (!err) { + err = set_downshift_time(dev, + PAW3395_REG_REST2_DOWNSHIFT, + CONFIG_PAW3395_REST2_DOWNSHIFT_TIME_MS); + } + + + // rest mode + if (!err) { + if(IS_ENABLED(CONFIG_PAW3395_ENABLE_REST)) + err = set_rest_mode(dev, true); + else + err = set_rest_mode(dev, false); + } + + // clear motion registers and ready to go + for (uint8_t reg = 0x02; (reg <= 0x06) && !err; reg++) { + uint8_t buf[1]; + err = reg_read(dev, reg, buf); + } + + if (err) { + LOG_ERR("Config the sensor failed"); + return err; + } + + return 0; +} + +// checked and keep +static void paw3395_async_init(struct k_work *work) +{ + struct pixart_data *data = CONTAINER_OF(work, struct pixart_data, + init_work); + const struct device *dev = data->dev; + + LOG_INF("PAW3395 async init step %d", data->async_init_step); + + data->err = async_init_fn[data->async_init_step](dev); + if (data->err) { + LOG_ERR("PAW3395 initialization failed"); + } else { + data->async_init_step++; + + if (data->async_init_step == ASYNC_INIT_STEP_COUNT) { + data->ready = true; // sensor is ready to work + LOG_INF("PAW3395 initialized"); + } else { + k_work_schedule(&data->init_work, + K_MSEC(async_init_delay[data->async_init_step])); + } + } +} + + +static void irq_handler(const struct device *gpiob, struct gpio_callback *cb, + uint32_t pins) +{ + int err; + struct pixart_data *data = CONTAINER_OF(cb, struct pixart_data, + irq_gpio_cb); + const struct device *dev = data->dev; + const struct pixart_config *config = dev->config; + + // disable the interrupt line first + err = gpio_pin_interrupt_configure_dt(&config->irq_gpio, + GPIO_INT_DISABLE); + if (unlikely(err)) { + LOG_ERR("Cannot disable IRQ"); + k_panic(); + } + + // submit the real handler work + k_work_submit(&data->trigger_handler_work); +} + +static void trigger_handler(struct k_work *work) +{ + LOG_DBG("trigger_handler"); + + sensor_trigger_handler_t handler; + int err = 0; + struct pixart_data *data = CONTAINER_OF(work, struct pixart_data, + trigger_handler_work); + const struct device *dev = data->dev; + const struct pixart_config *config = dev->config; + + // 1. the first lock period is used to procoss the trigger + // if data_ready_handler is non-NULL, otherwise do nothing + k_spinlock_key_t key = k_spin_lock(&data->lock); + + handler = data->data_ready_handler; + k_spin_unlock(&data->lock, key); + + if (!handler) { + LOG_DBG("no trigger handler set by application code"); + return; + } + + handler(dev, data->trigger); + + // 2. the second lock period is used to resume the interrupt line + // if data_ready_handler is non-NULL, otherwise keep it inactive + key = k_spin_lock(&data->lock); + if (data->data_ready_handler) { + err = gpio_pin_interrupt_configure_dt(&config->irq_gpio, + GPIO_INT_LEVEL_ACTIVE); + } + k_spin_unlock(&data->lock, key); + + if (unlikely(err)) { + LOG_ERR("Cannot re-enable IRQ"); + k_panic(); + } +} + +static int paw3395_init_irq(const struct device *dev) +{ + LOG_INF("Configure irq..."); + + int err; + struct pixart_data *data = dev->data; + const struct pixart_config *config = dev->config; + + // check readiness of irq gpio pin + if (!device_is_ready(config->irq_gpio.port)) { + LOG_ERR("IRQ GPIO device not ready"); + return -ENODEV; + } + + // init the irq pin + err = gpio_pin_configure_dt(&config->irq_gpio, GPIO_INPUT); + if (err) { + LOG_ERR("Cannot configure IRQ GPIO"); + return err; + } + + // setup and add the irq callback associated + gpio_init_callback(&data->irq_gpio_cb, irq_handler, + BIT(config->irq_gpio.pin)); + + err = gpio_add_callback(config->irq_gpio.port, &data->irq_gpio_cb); + if (err) { + LOG_ERR("Cannot add IRQ GPIO callback"); + } + + LOG_INF("Configure irq done"); + + return err; +} + +static int paw3395_init(const struct device *dev) +{ + LOG_INF("Start initializing..."); + + struct pixart_data *data = dev->data; + const struct pixart_config *config = dev->config; + int err; + + // init device pointer + data->dev = dev; + + // init trigger handler work + k_work_init(&data->trigger_handler_work, trigger_handler); + + // check readiness of spi bus + if (!spi_is_ready(&config->bus)) { + LOG_ERR("SPI device not ready"); + return -ENODEV; + } + + // check readiness of cs gpio pin and init it to inactive + if (!device_is_ready(config->cs_gpio.port)) { + LOG_ERR("SPI CS device not ready"); + return -ENODEV; + } + + err = gpio_pin_configure_dt(&config->cs_gpio, GPIO_OUTPUT_INACTIVE); + if (err) { + LOG_ERR("Cannot configure SPI CS GPIO"); + return err; + } + + // init irq routine + err = paw3395_init_irq(dev); + if (err) { + return err; + } + + // Setup delayable and non-blocking init jobs, including following steps: + // 1. power reset + // 2. upload initial settings + // 3. other configs like cpi, downshift time, sample time etc. + // The sensor is ready to work (i.e., data->ready=true after the above steps are finished) + k_work_init_delayable(&data->init_work, paw3395_async_init); + + k_work_schedule(&data->init_work, + K_MSEC(async_init_delay[data->async_init_step])); + + return err; +} + +static int paw3395_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct pixart_data *data = dev->data; + uint8_t buf[PAW3395_BURST_SIZE]; + + if (unlikely(chan != SENSOR_CHAN_ALL)) { + return -ENOTSUP; + } + + if (unlikely(!data->ready)) { + LOG_DBG("Device is not initialized yet"); + return -EBUSY; + } + + int err = motion_burst_read(dev, buf, sizeof(buf)); + + if (!err) { + int16_t x = ((int16_t)sys_get_le16(&buf[PAW3395_DX_POS])) / CONFIG_PAW3395_CPI_DIVIDOR; + int16_t y = ((int16_t)sys_get_le16(&buf[PAW3395_DY_POS])) / CONFIG_PAW3395_CPI_DIVIDOR; + /* int16_t x = sys_get_le16(&buf[PAW3395_DX_POS]); */ + /* int16_t y = sys_get_le16(&buf[PAW3395_DY_POS]); */ + + if (IS_ENABLED(CONFIG_PAW3395_ORIENTATION_0)) { + data->x = x; + data->y = y; + } else if (IS_ENABLED(CONFIG_PAW3395_ORIENTATION_90)) { + data->x = y; + data->y = x; + } else if (IS_ENABLED(CONFIG_PAW3395_ORIENTATION_180)) { + data->x = x; + data->y = -y; + } else if (IS_ENABLED(CONFIG_PAW3395_ORIENTATION_270)) { + data->x = -y; + data->y = -x; + } + } + + return err; +} + +static int paw3395_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct pixart_data *data = dev->data; + + if (unlikely(!data->ready)) { + LOG_DBG("Device is not initialized yet"); + return -EBUSY; + } + + switch (chan) { + case SENSOR_CHAN_POS_DX: + val->val1 = data->x; + val->val2 = 0; + break; + + case SENSOR_CHAN_POS_DY: + val->val1 = data->y; + val->val2 = 0; + break; + + default: + return -ENOTSUP; + } + + return 0; +} + +/* Setup the callback for actual trigger handling */ +// handler could be NULL, in which case the effect is disabling the interrupt line +// Thus it has dual function: +// 1. set up a handler callback +// 2. set up a flag (i.e., data_ready_handler) to indicate resuming the interrput line or not +// This feature is useful to pass the resuming of the interrupt to application +static int paw3395_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + LOG_INF("trigger_set"); + + struct pixart_data *data = dev->data; + const struct pixart_config *config = dev->config; + int err; + + if (unlikely(trig->type != SENSOR_TRIG_DATA_READY)) { + return -ENOTSUP; + } + + if (unlikely(trig->chan != SENSOR_CHAN_ALL)) { + return -ENOTSUP; + } + + if (unlikely(!data->ready)) { + LOG_DBG("Device is not initialized yet"); + return -EBUSY; + } + + // spin lock is needed, so that the handler is not invoked before its pointer is assigned + // a valid value + k_spinlock_key_t key = k_spin_lock(&data->lock); + + // if non-NULL (a real handler defined), eanble the interrupt line + // otherwise, disable the interrupt line + if (handler) { + err = gpio_pin_interrupt_configure_dt(&config->irq_gpio, + GPIO_INT_LEVEL_ACTIVE); + } else { + err = gpio_pin_interrupt_configure_dt(&config->irq_gpio, + GPIO_INT_DISABLE); + } + + if (!err) { + data->data_ready_handler = handler; + } + + data->trigger = trig; + + k_spin_unlock(&data->lock, key); + + return err; +} + +static const struct sensor_driver_api paw3395_driver_api = { + .sample_fetch = paw3395_sample_fetch, + .channel_get = paw3395_channel_get, + .trigger_set = paw3395_trigger_set, + .attr_set = paw3395_attr_set, +}; + +#define PAW3395_DEFINE(n) \ + static struct pixart_data data##n; \ + \ + static const struct pixart_config config##n = { \ + .irq_gpio = GPIO_DT_SPEC_INST_GET(n, irq_gpios), \ + .bus = { \ + .bus = DEVICE_DT_GET(DT_INST_BUS(n)), \ + .config = { \ + .frequency = DT_INST_PROP(n, \ + spi_max_frequency), \ + .operation = SPI_WORD_SET(8) | \ + SPI_TRANSFER_MSB | \ + SPI_MODE_CPOL | SPI_MODE_CPHA, \ + .slave = DT_INST_REG_ADDR(n), \ + }, \ + }, \ + .cs_gpio = SPI_CS_GPIOS_DT_SPEC_GET(DT_DRV_INST(n)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, paw3395_init, NULL, &data##n, &config##n, \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &paw3395_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(PAW3395_DEFINE) diff --git a/app/drivers/sensor/pixart/paw3395/paw3395.h b/app/drivers/sensor/pixart/paw3395/paw3395.h new file mode 100644 index 00000000000..7c849c66200 --- /dev/null +++ b/app/drivers/sensor/pixart/paw3395/paw3395.h @@ -0,0 +1,65 @@ +#ifndef ZEPHYR_INCLUDE_PAW3395_H_ +#define ZEPHYR_INCLUDE_PAW3395_H_ + +#include "../pixart.h" + +/** + * @file paw3395.h + * + * @brief Header file for the paw3395 driver. + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + enum paw3395_run_mode { + HP_MODE, // high performance mode (the default mode using standard power-up register sets) + LP_MODE, // low power mode + OFFICE_MODE, // office mode (reduced to 10 ips, most power-efficient) + GAME_MODE, // corded game mode (with best performance and highest power consumption) + + RUN_MODE_COUNT // end flag + }; + +enum paw3395_attribute { + /** Sensor CPI for both X and Y axes. */ + PAW3395_ATTR_X_CPI = SENSOR_ATTR_PRIV_START, + + PAW3395_ATTR_Y_CPI, + + /** Enable or disable sleep modes. */ + PAW3395_ATTR_REST_ENABLE, + + /** Entering time from Run mode to REST1 mode [ms]. */ + PAW3395_ATTR_RUN_DOWNSHIFT_TIME, + + /** Entering time from REST1 mode to REST2 mode [ms]. */ + PAW3395_ATTR_REST1_DOWNSHIFT_TIME, + + /** Entering time from REST2 mode to REST3 mode [ms]. */ + PAW3395_ATTR_REST2_DOWNSHIFT_TIME, + + /** Sampling frequency time during REST1 mode [ms]. */ + PAW3395_ATTR_REST1_SAMPLE_TIME, + + /** Sampling frequency time during REST2 mode [ms]. */ + PAW3395_ATTR_REST2_SAMPLE_TIME, + + /** Sampling frequency time during REST3 mode [ms]. */ + PAW3395_ATTR_REST3_SAMPLE_TIME, + + /** Select run mde. */ + PAW3395_ATTR_RUN_MODE, +}; +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_PAW3395_H_ */ diff --git a/app/drivers/sensor/pixart/paw3395/paw3395_priv.c b/app/drivers/sensor/pixart/paw3395/paw3395_priv.c new file mode 100644 index 00000000000..a2445400bcd --- /dev/null +++ b/app/drivers/sensor/pixart/paw3395/paw3395_priv.c @@ -0,0 +1,117 @@ +#include +#include +#include "paw3395.h" + +///////// Init setting registers ////////////////////// +const size_t paw3395_pwrup_registers_length1 = 137; +const size_t paw3395_pwrup_registers_length2 = 5; + +/* power up registers init: group1 */ +const uint8_t paw3395_pwrup_registers_addr1[] = { + 0x7F, 0x40, 0x7F, 0x40, 0x7F, 0x55, 0x56, 0x57, 0x58, 0x7F, + 0x42, 0x43, 0x4B, 0x4D, 0x53, 0x7F, 0x44, 0x4D, 0x51, 0x53, + 0x55, 0x5A, 0x5B, 0x61, 0x62, 0x6D, 0x6E, 0x70, 0x4A, 0x60, + 0x7F, 0x6C, 0x6D, 0x6E, 0x53, 0x55, 0x7A, 0x7D, 0x7F, 0x41, + 0x42, 0x43, 0x7F, 0x71, 0x7F, 0x62, 0x63, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6A, 0x6C, 0x6D, 0x51, 0x53, 0x54, 0x71, 0x72, + 0x73, 0x7F, 0x4A, 0x4C, 0x55, 0x7F, 0x4B, 0x4C, 0x61, 0x62, + 0x63, 0x7F, 0x4C, 0x56, 0x41, 0x4D, 0x7F, 0x4A, 0x4B, 0x4C, + 0x41, 0x55, 0x56, 0x49, 0x42, 0x43, 0x44, 0x54, 0x5A, 0x5F, + 0x5B, 0x5E, 0x7F, 0x48, 0x4F, 0x52, 0x51, 0x54, 0x53, 0x56, + 0x55, 0x58, 0x57, 0x5A, 0x5B, 0x5C, 0x5D, 0x71, 0x70, 0x73, + 0x72, 0x75, 0x74, 0x77, 0x76, 0x7F, 0x4C, 0x7F, 0x4F, 0x4E, + 0x52, 0x51, 0x54, 0x5A, 0x77, 0x47, 0x5B, 0x64, 0x65, 0x66, + 0x67, 0x78, 0x79, 0x40, 0x55, 0x23, 0x22 +}; +const uint8_t paw3395_pwrup_registers_data1[] = { + 0x07, 0x41, 0x00, 0x80, 0x0E, 0x0D, 0x1B, 0xE8, 0xD5, 0x14, + 0xBC, 0x74, 0x20, 0x00, 0x0E, 0x05, 0x04, 0x06, 0x40, 0x40, + 0xCA, 0xE8, 0xEA, 0x31, 0x64, 0xB8, 0x0F, 0x02, 0x2A, 0x26, + 0x06, 0x70, 0x60, 0x04, 0x02, 0x11, 0x01, 0x51, 0x07, 0x10, + 0x32, 0x00, 0x08, 0x4F, 0x09, 0x1F, 0x1F, 0x03, 0x03, 0x1F, + 0x1F, 0x03, 0x03, 0x1F, 0x1F, 0x04, 0x20, 0x20, 0x0C, 0x07, + 0x07, 0x0A, 0x14, 0x14, 0x19, 0x14, 0x30, 0x03, 0x0B, 0x0A, + 0x02, 0x15, 0x02, 0x02, 0x91, 0x0A, 0x0C, 0x10, 0x0C, 0x40, + 0x25, 0x18, 0x14, 0x0A, 0x00, 0x2D, 0x0C, 0x1A, 0x0D, 0x1E, + 0x05, 0x0F, 0x0D, 0xDD, 0x03, 0x49, 0x00, 0x5B, 0x00, 0x64, + 0x00, 0xA5, 0x02, 0x29, 0x47, 0x81, 0x40, 0xDC, 0x07, 0x00, + 0x08, 0xDC, 0x07, 0x00, 0x08, 0x10, 0xD0, 0x00, 0x63, 0x00, + 0x63, 0x00, 0x54, 0x10, 0x4F, 0x01, 0x40, 0x60, 0x06, 0x13, + 0x0F, 0x01, 0x9C, 0x00, 0x02, 0x70, 0x01 +}; + +/* power up registers init: group2 */ +const uint8_t paw3395_pwrup_registers_addr2[] = { + 0x22, 0x55, 0x7F, 0x40, 0x7F +}; +const uint8_t paw3395_pwrup_registers_data2[] = { + 0x00, 0x00, 0x07, 0x40, 0x00 +}; + +///////// Run mode registers ////////////////////// +const size_t paw3395_mode_registers_length[RUN_MODE_COUNT] = { + [HP_MODE] = 21, + [LP_MODE] = 21, + [OFFICE_MODE] = 21, + [GAME_MODE] = 19, +}; + +/* hp mode registers */ +const uint8_t paw3395_hp_register_addr[] = { + 0x7F, 0x51, 0x53, 0x61, 0x6E, 0x7F, 0x42, 0x43, 0x7F, 0x51, + 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x7F, 0x54, 0x78, + 0x79 +}; +const uint8_t paw3395_hp_register_data[] = { + 0x05, 0x40, 0x40, 0x31, 0x0F, 0x07, 0x32, 0x00, 0x0D, 0x00, + 0x49, 0x00, 0x5B, 0x00, 0x64, 0x02, 0xA5, 0x00, 0x54, 0x01, + 0x9C +}; + +/* lp mode registers */ +const uint8_t paw3395_lp_register_addr[] = { + 0x7F, 0x51, 0x53, 0x61, 0x6E, 0x7F, 0x42, 0x43, 0x7F, 0x51, + 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x7F, 0x54, 0x78, + 0x79 +}; +const uint8_t paw3395_lp_register_data[] = { + 0x05, 0x40, 0x40, 0x3B, 0x1F, 0x07, 0x32, 0x00, 0x0D, 0x00, + 0x49, 0x00, 0x5B, 0x00, 0x64, 0x02, 0xA5, 0x00, 0x54, 0x01, + 0x9C +}; + +/* office mode registers */ +const uint8_t paw3395_office_register_addr[] = { + 0x7F, 0x51, 0x53, 0x61, 0x6E, 0x7F, 0x42, 0x43, 0x7F, 0x51, + 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x7F, 0x54, 0x78, + 0x79 +}; +const uint8_t paw3395_office_register_data[] = { + 0x05, 0x28, 0x30, 0x3B, 0x1F, 0x07, 0x32, 0x00, 0x0D, 0x00, + 0x49, 0x00, 0x5B, 0x00, 0x64, 0x02, 0xA5, 0x00, 0x52, 0x0A, + 0x0F +}; + +/* game mode registers */ +const uint8_t paw3395_game_register_addr[] = { + 0x7F, 0x51, 0x53, 0x61, 0x6E, 0x7F, 0x42, 0x43, 0x7F, 0x51, + 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x7F, 0x54 +}; +const uint8_t paw3395_game_register_data[] = { + 0x05, 0x40, 0x40, 0x31, 0x0F, 0x07, 0x2F, 0x00, 0x0D, 0x12, + 0xDB, 0x12, 0xDC, 0x12, 0xEA, 0x15, 0x2D, 0x00, 0x55 +}; + +/* aggregation of all run modes registers */ +const uint8_t* paw3395_mode_registers_addr[] = { + [HP_MODE] = paw3395_hp_register_addr, + [LP_MODE] = paw3395_lp_register_addr, + [OFFICE_MODE] = paw3395_office_register_addr, + [GAME_MODE] = paw3395_game_register_addr, +}; +const uint8_t* paw3395_mode_registers_data[] = { + [HP_MODE] = paw3395_hp_register_data, + [LP_MODE] = paw3395_lp_register_data, + [OFFICE_MODE] = paw3395_office_register_data, + [GAME_MODE] = paw3395_game_register_data, +}; diff --git a/app/drivers/sensor/pixart/pixart.h b/app/drivers/sensor/pixart/pixart.h new file mode 100644 index 00000000000..13caf385dbc --- /dev/null +++ b/app/drivers/sensor/pixart/pixart.h @@ -0,0 +1,103 @@ +#ifndef ZEPHYR_INCLUDE_PIXART_H_ +#define ZEPHYR_INCLUDE_PIXART_H_ + +/** + * @file pixart.h + * + * @brief Common header file for all optical motion sensor by PIXART + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* device data structure */ + struct pixart_data { + const struct device *dev; + int16_t x; + int16_t y; + + // lock is needed to keep atomic of the trigger handler upadting + struct k_spinlock lock; + // motion interrupt isr + struct gpio_callback irq_gpio_cb; + // the actual trigger handler. This handler also used to flag whether resuming the motion interrupt line + sensor_trigger_handler_t data_ready_handler; + const struct sensor_trigger *trigger; + // the work structure holding the trigger handler job + struct k_work trigger_handler_work; + + // the work structure for delayable init steps + struct k_work_delayable init_work; + int async_init_step; + + // + bool ready; // whether init is finished successfully + bool last_read_burst; // todo: needed? + int err; // error code during async init + + /* the design of the driver is based on interrupt purely, to add polling upon it + the following work and timer maybe used in application code */ + struct k_work poll_work; + struct k_timer poll_timer; + + // for pmw3610 smart algorithm + bool sw_smart_flag; + }; + + // device config data structure + struct pixart_config { + struct gpio_dt_spec irq_gpio; + struct spi_dt_spec bus; + struct gpio_dt_spec cs_gpio; + }; + +/** @brief Sensor specific attributes of PIXART. */ +enum pixart_attribute { + /** Sensor CPI for both X and Y axes. */ + PIXART_ATTR_CPI = SENSOR_ATTR_PRIV_START, + + /** Sensor CPI for X and Y axes. */ + PIXART_ATTR_XCPI, + PIXART_ATTR_YCPI, + + /** Enable or disable sleep modes. */ + PIXART_ATTR_REST_ENABLE, + + /** Entering time from Run mode to REST1 mode [ms]. */ + PIXART_ATTR_RUN_DOWNSHIFT_TIME, + + /** Entering time from REST1 mode to REST2 mode [ms]. */ + PIXART_ATTR_REST1_DOWNSHIFT_TIME, + + /** Entering time from REST2 mode to REST3 mode [ms]. */ + PIXART_ATTR_REST2_DOWNSHIFT_TIME, + + /** Sampling frequency time during REST1 mode [ms]. */ + PIXART_ATTR_REST1_SAMPLE_TIME, + + /** Sampling frequency time during REST2 mode [ms]. */ + PIXART_ATTR_REST2_SAMPLE_TIME, + + /** Sampling frequency time during REST3 mode [ms]. */ + PIXART_ATTR_REST3_SAMPLE_TIME, + + /** Select the running mode. */ + PIXART_ATTR_RUN_MODE, +}; + + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_PIXART_H_ */ diff --git a/app/drivers/sensor/pixart/pmw3360/CMakeLists.txt b/app/drivers/sensor/pixart/pmw3360/CMakeLists.txt new file mode 100644 index 00000000000..d08e76f799b --- /dev/null +++ b/app/drivers/sensor/pixart/pmw3360/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +zephyr_library() + +zephyr_library_sources(pmw3360.c) +zephyr_library_sources(pmw3360_priv.c) diff --git a/app/drivers/sensor/pixart/pmw3360/Kconfig b/app/drivers/sensor/pixart/pmw3360/Kconfig new file mode 100644 index 00000000000..863835cc567 --- /dev/null +++ b/app/drivers/sensor/pixart/pmw3360/Kconfig @@ -0,0 +1,76 @@ +# Sensor data simulator +# +# Copyright (c) 2019 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +menuconfig PMW3360 + bool "PMW3360 mouse optical sensor" + select SPI + help + Enable PMW3360 mouse optical sensor. + +if PMW3360 + +config PMW3360_CPI + int "PMW3360's default CPI" + default 1600 + range 100 12000 + help + Default CPI value. + +config PMW3360_CPI_DIVIDOR + int "PMW3360's default CPI dividor" + default 4 + range 1 12 + help + Default CPI dividor value. + +config PMW3360_RUN_DOWNSHIFT_TIME_MS + int "PMW3360's default RUN mode downshift time" + default 500 + range 10 2550 + help + Default RUN mode downshift down time in milliseconds. + Time after which sensor goes from RUN to REST1 mode. + +config PMW3360_REST1_DOWNSHIFT_TIME_MS + int "PMW3360's default REST1 mode downshift time" + default 9220 + range 320 81600 + help + Default REST1 mode downshift down time in milliseconds. + Time after which sensor goes from REST1 to REST2 mode. + +config PMW3360_REST2_DOWNSHIFT_TIME_MS + int "PMW3360's default REST2 mode downshift time" + default 150000 + range 3200 816000 + help + Default REST2 mode downshift down time in milliseconds. + Time after which sensor goes from REST2 to REST3 mode. + +choice + prompt "Select PMW3360 sensor orientation" + default PMW3360_ORIENTATION_0 + +config PMW3360_ORIENTATION_0 + bool "PMW3360 not rotated" + +config PMW3360_ORIENTATION_90 + bool "PMW3360 rotated 90 deg clockwise" + +config PMW3360_ORIENTATION_180 + bool "PMW3360 rotated 180 deg clockwise" + +config PMW3360_ORIENTATION_270 + bool "PMW3360 rotated 270 deg clockwise" + +endchoice + +module = PMW3360 +module-str = PMW3360 +source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config" + +endif #PMW3360 diff --git a/app/drivers/sensor/pixart/pmw3360/pmw3360.c b/app/drivers/sensor/pixart/pmw3360/pmw3360.c new file mode 100644 index 00000000000..5361d4f354f --- /dev/null +++ b/app/drivers/sensor/pixart/pmw3360/pmw3360.c @@ -0,0 +1,988 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT pixart_pmw3360 + +#include +#include +#include "pmw3360.h" + +#include +LOG_MODULE_REGISTER(pmw3360, CONFIG_PMW3360_LOG_LEVEL); + +/* Timings defined by spec (in us) */ +#define T_NCS_SCLK 1 /* 120 ns (rounded to 1us?)*/ +#define T_SRX (20 - T_NCS_SCLK) /* 20 us */ +#define T_SCLK_NCS_WR (35 - T_NCS_SCLK) /* 35 us */ +#define T_SWX (180 - T_SCLK_NCS_WR) /* 180 us */ +#define T_SRAD 160 /* 160 us */ +#define T_SRAD_MOTBR 35 /* 35 us */ +#define T_BEXIT 1 /* 500 ns (rounded to 1us?)*/ + +/* Timing defined on SROM download burst mode figure */ +#define T_BRSEP 15 /* 15 us */ + +/* Sensor registers */ +#define PMW3360_REG_PRODUCT_ID 0x00 +#define PMW3360_REG_REVISION_ID 0x01 +#define PMW3360_REG_MOTION 0x02 +#define PMW3360_REG_DELTA_X_L 0x03 +#define PMW3360_REG_DELTA_X_H 0x04 +#define PMW3360_REG_DELTA_Y_L 0x05 +#define PMW3360_REG_DELTA_Y_H 0x06 +#define PMW3360_REG_SQUAL 0x07 +#define PMW3360_REG_RAW_DATA_SUM 0x08 +#define PMW3360_REG_MAXIMUM_RAW_DATA 0x09 +#define PMW3360_REG_MINIMUM_RAW_DATA 0x0A +#define PMW3360_REG_SHUTTER_LOWER 0x0B +#define PMW3360_REG_SHUTTER_UPPER 0x0C +#define PMW3360_REG_CONTROL 0x0D +#define PMW3360_REG_CONFIG1 0x0F +#define PMW3360_REG_CONFIG2 0x10 +#define PMW3360_REG_ANGLE_TUNE 0x11 +#define PMW3360_REG_FRAME_CAPTURE 0x12 +#define PMW3360_REG_SROM_ENABLE 0x13 +#define PMW3360_REG_RUN_DOWNSHIFT 0x14 +#define PMW3360_REG_REST1_RATE_LOWER 0x15 +#define PMW3360_REG_REST1_RATE_UPPER 0x16 +#define PMW3360_REG_REST1_DOWNSHIFT 0x17 +#define PMW3360_REG_REST2_RATE_LOWER 0x18 +#define PMW3360_REG_REST2_RATE_UPPER 0x19 +#define PMW3360_REG_REST2_DOWNSHIFT 0x1A +#define PMW3360_REG_REST3_RATE_LOWER 0x1B +#define PMW3360_REG_REST3_RATE_UPPER 0x1C +#define PMW3360_REG_OBSERVATION 0x24 +#define PMW3360_REG_DATA_OUT_LOWER 0x25 +#define PMW3360_REG_DATA_OUT_UPPER 0x26 +#define PMW3360_REG_RAW_DATA_DUMP 0x29 +#define PMW3360_REG_SROM_ID 0x2A +#define PMW3360_REG_MIN_SQ_RUN 0x2B +#define PMW3360_REG_RAW_DATA_THRESHOLD 0x2C +#define PMW3360_REG_CONFIG5 0x2F +#define PMW3360_REG_POWER_UP_RESET 0x3A +#define PMW3360_REG_SHUTDOWN 0x3B +#define PMW3360_REG_INVERSE_PRODUCT_ID 0x3F +#define PMW3360_REG_LIFTCUTOFF_TUNE3 0x41 +#define PMW3360_REG_ANGLE_SNAP 0x42 +#define PMW3360_REG_LIFTCUTOFF_TUNE1 0x4A +#define PMW3360_REG_MOTION_BURST 0x50 +#define PMW3360_REG_LIFTCUTOFF_TUNE_TIMEOUT 0x58 +#define PMW3360_REG_LIFTCUTOFF_TUNE_MIN_LENGTH 0x5A +#define PMW3360_REG_SROM_LOAD_BURST 0x62 +#define PMW3360_REG_LIFT_CONFIG 0x63 +#define PMW3360_REG_RAW_DATA_BURST 0x64 +#define PMW3360_REG_LIFTCUTOFF_TUNE2 0x65 + +/* Sensor identification values */ +#define PMW3360_PRODUCT_ID 0x42 +#define PMW3360_FIRMWARE_ID 0x04 + +/* Power-up register commands */ +#define PMW3360_POWERUP_CMD_RESET 0x5A + +/* Max register count readable in a single motion burst */ +#define PMW3360_MAX_BURST_SIZE 12 + +/* Register count used for reading a single motion burst */ +#define PMW3360_BURST_SIZE 6 + +/* Position of X in motion burst data */ +#define PMW3360_DX_POS 2 +#define PMW3360_DY_POS 4 + +/* Rest_En position in Config2 register. */ +#define PMW3360_REST_EN_POS 5 + +#define PMW3360_MAX_CPI 12000 +#define PMW3360_MIN_CPI 100 + +#define SPI_WRITE_BIT BIT(7) + +/* Helper macros used to convert sensor values. */ +#define PMW3360_SVALUE_TO_CPI(svalue) ((uint32_t)(svalue).val1) +#define PMW3360_SVALUE_TO_TIME(svalue) ((uint32_t)(svalue).val1) +#define PMW3360_SVALUE_TO_BOOL(svalue) ((svalue).val1 != 0) + +/* SROM firmware meta-data, defined in pmw3360_piv.c */ +extern const size_t pmw3360_firmware_length; +extern const uint8_t pmw3360_firmware_data[]; + +/* sensor initialization steps definition */ +// init is done in non-blocking manner (i.e., async), a delayable work is defined for this job +// see pmw3360_init and pmw3360_async_init) + +enum async_init_step { + ASYNC_INIT_STEP_POWER_UP, // power up reset + ASYNC_INIT_STEP_FW_LOAD_START, // clear motion registers, disable REST mode, enable SROM + // register + ASYNC_INIT_STEP_FW_LOAD_CONTINUE, // start SROM download + ASYNC_INIT_STEP_FW_LOAD_VERIFY, // verify SROM pid and fid, enable REST mode + ASYNC_INIT_STEP_CONFIGURE, // set cpi and donwshift time (run, rest1, rest2) + + ASYNC_INIT_STEP_COUNT // end flag +}; + +// delay (ms) in between steps +static const int32_t async_init_delay[ASYNC_INIT_STEP_COUNT] = { + [ASYNC_INIT_STEP_POWER_UP] = 1, + [ASYNC_INIT_STEP_FW_LOAD_START] = 50, // required in spec + [ASYNC_INIT_STEP_FW_LOAD_CONTINUE] = 10, // required in spec + [ASYNC_INIT_STEP_FW_LOAD_VERIFY] = 1, + [ASYNC_INIT_STEP_CONFIGURE] = 0, +}; + +static int pmw3360_async_init_power_up(const struct device *dev); +static int pmw3360_async_init_configure(const struct device *dev); +static int pmw3360_async_init_fw_load_verify(const struct device *dev); +static int pmw3360_async_init_fw_load_continue(const struct device *dev); +static int pmw3360_async_init_fw_load_start(const struct device *dev); + +static int (*const async_init_fn[ASYNC_INIT_STEP_COUNT])(const struct device *dev) = { + [ASYNC_INIT_STEP_POWER_UP] = pmw3360_async_init_power_up, + [ASYNC_INIT_STEP_FW_LOAD_START] = pmw3360_async_init_fw_load_start, + [ASYNC_INIT_STEP_FW_LOAD_CONTINUE] = pmw3360_async_init_fw_load_continue, + [ASYNC_INIT_STEP_FW_LOAD_VERIFY] = pmw3360_async_init_fw_load_verify, + [ASYNC_INIT_STEP_CONFIGURE] = pmw3360_async_init_configure, +}; + +static int spi_cs_ctrl(const struct device *dev, bool enable) { + const struct pixart_config *config = dev->config; + int err; + + if (!enable) { + k_busy_wait(T_NCS_SCLK); + } + + err = gpio_pin_set_dt(&config->cs_gpio, (int)enable); + if (err) { + LOG_ERR("SPI CS ctrl failed"); + } + + if (enable) { + k_busy_wait(T_NCS_SCLK); + } + + return err; +} + +static int reg_read(const struct device *dev, uint8_t reg, uint8_t *buf) { + int err; + struct pixart_data *data = dev->data; + const struct pixart_config *config = dev->config; + + __ASSERT_NO_MSG((reg & SPI_WRITE_BIT) == 0); + + err = spi_cs_ctrl(dev, true); + if (err) { + return err; + } + + /* Write register address. */ + const struct spi_buf tx_buf = {.buf = ®, .len = 1}; + const struct spi_buf_set tx = {.buffers = &tx_buf, .count = 1}; + + err = spi_write_dt(&config->bus, &tx); + if (err) { + LOG_ERR("Reg read failed on SPI write"); + return err; + } + + k_busy_wait(T_SRAD); + + /* Read register value. */ + struct spi_buf rx_buf = { + .buf = buf, + .len = 1, + }; + const struct spi_buf_set rx = { + .buffers = &rx_buf, + .count = 1, + }; + + err = spi_read_dt(&config->bus, &rx); + if (err) { + LOG_ERR("Reg read failed on SPI read"); + return err; + } + + err = spi_cs_ctrl(dev, false); + if (err) { + return err; + } + + k_busy_wait(T_SRX); + + data->last_read_burst = false; + + return 0; +} + +static int reg_write(const struct device *dev, uint8_t reg, uint8_t val) { + int err; + struct pixart_data *data = dev->data; + const struct pixart_config *config = dev->config; + + __ASSERT_NO_MSG((reg & SPI_WRITE_BIT) == 0); + + err = spi_cs_ctrl(dev, true); + if (err) { + return err; + } + + uint8_t buf[] = {SPI_WRITE_BIT | reg, val}; + const struct spi_buf tx_buf = {.buf = buf, .len = ARRAY_SIZE(buf)}; + const struct spi_buf_set tx = {.buffers = &tx_buf, .count = 1}; + + err = spi_write_dt(&config->bus, &tx); + if (err) { + LOG_ERR("Reg write failed on SPI write"); + return err; + } + + k_busy_wait(T_SCLK_NCS_WR); + + err = spi_cs_ctrl(dev, false); + if (err) { + return err; + } + + k_busy_wait(T_SWX); + + data->last_read_burst = false; + + return 0; +} + +static int motion_burst_read(const struct device *dev, uint8_t *buf, size_t burst_size) { + int err; + struct pixart_data *data = dev->data; + const struct pixart_config *config = dev->config; + + __ASSERT_NO_MSG(burst_size <= PMW3360_MAX_BURST_SIZE); + + /* Write any value to motion burst register only if there have been + * other SPI transmissions with sensor since last burst read. + */ + if (!data->last_read_burst) { + err = reg_write(dev, PMW3360_REG_MOTION_BURST, 0x00); + if (err) { + return err; + } + } + + err = spi_cs_ctrl(dev, true); + if (err) { + return err; + } + + /* Send motion burst address */ + uint8_t reg_buf[] = {PMW3360_REG_MOTION_BURST}; + const struct spi_buf tx_buf = {.buf = reg_buf, .len = ARRAY_SIZE(reg_buf)}; + const struct spi_buf_set tx = {.buffers = &tx_buf, .count = 1}; + + err = spi_write_dt(&config->bus, &tx); + if (err) { + LOG_ERR("Motion burst failed on SPI write"); + return err; + } + + k_busy_wait(T_SRAD_MOTBR); + + const struct spi_buf rx_buf = { + .buf = buf, + .len = burst_size, + }; + const struct spi_buf_set rx = {.buffers = &rx_buf, .count = 1}; + + err = spi_read_dt(&config->bus, &rx); + if (err) { + LOG_ERR("Motion burst failed on SPI read"); + return err; + } + + /* Terminate burst */ + err = spi_cs_ctrl(dev, false); + if (err) { + return err; + } + + k_busy_wait(T_BEXIT); + + data->last_read_burst = true; + + return 0; +} + +static int burst_write(const struct device *dev, uint8_t reg, const uint8_t *buf, size_t size) { + int err; + struct pixart_data *data = dev->data; + const struct pixart_config *config = dev->config; + + /* Write address of burst register */ + uint8_t write_buf = reg | SPI_WRITE_BIT; + struct spi_buf tx_buf = {.buf = &write_buf, .len = 1}; + const struct spi_buf_set tx = {.buffers = &tx_buf, .count = 1}; + + err = spi_cs_ctrl(dev, true); + if (err) { + return err; + } + + err = spi_write_dt(&config->bus, &tx); + if (err) { + LOG_ERR("Burst write failed on SPI write"); + return err; + } + + /* Write data */ + for (size_t i = 0; i < size; i++) { + write_buf = buf[i]; + + err = spi_write_dt(&config->bus, &tx); + if (err) { + LOG_ERR("Burst write failed on SPI write (data)"); + return err; + } + + k_busy_wait(T_BRSEP); + } + + /* Terminate burst mode. */ + err = spi_cs_ctrl(dev, false); + if (err) { + return err; + } + + k_busy_wait(T_BEXIT); + + data->last_read_burst = false; + + return 0; +} + +static int set_cpi(const struct device *dev, uint32_t cpi) { + /* Set resolution with CPI step of 100 cpi + * 0x00: 100 cpi (minimum cpi) + * 0x01: 200 cpi + * : + * 0x31: 5000 cpi (default cpi) + * : + * 0x77: 12000 cpi (maximum cpi) + */ + + if ((cpi > PMW3360_MAX_CPI) || (cpi < PMW3360_MIN_CPI)) { + LOG_ERR("CPI value %u out of range", cpi); + return -EINVAL; + } + + /* Convert CPI to register value */ + uint8_t value = (cpi / 100) - 1; + + LOG_INF("Setting CPI to %u (reg value 0x%x)", cpi, value); + + int err = reg_write(dev, PMW3360_REG_CONFIG1, value); + if (err) { + LOG_ERR("Failed to change CPI"); + } + + return err; +} + +/* unit: ms */ +static int set_downshift_time(const struct device *dev, uint8_t reg_addr, uint32_t time) { + /* Set downshift time in ms: + * - Run downshift time (from Run to Rest1 mode), default: 500ms + * - Rest 1 downshift time (from Rest1 to Rest2 mode), default: 9.92 s + * - Rest 2 downshift time (from Rest2 to Rest3 mode), default: ~10 min + */ + uint32_t maxtime; + uint32_t mintime; + + switch (reg_addr) { + case PMW3360_REG_RUN_DOWNSHIFT: + /* + * Run downshift time = PMW3360_REG_RUN_DOWNSHIFT * 10 ms + */ + maxtime = 2550; + mintime = 10; + break; + + case PMW3360_REG_REST1_DOWNSHIFT: + /* + * Rest1 downshift time = PMW3360_REG_RUN_DOWNSHIFT + * * 320 * Rest1 rate (default 1 ms) + */ + maxtime = 81600; + mintime = 320; + break; + + case PMW3360_REG_REST2_DOWNSHIFT: + /* + * Rest2 downshift time = PMW3360_REG_REST2_DOWNSHIFT + * * 32 * Rest2 rate (default 100 ms) + */ + maxtime = 816000; + mintime = 3200; + break; + + default: + LOG_ERR("Not supported"); + return -ENOTSUP; + } + + if ((time > maxtime) || (time < mintime)) { + LOG_WRN("Downshift time %u out of range", time); + return -EINVAL; + } + + __ASSERT_NO_MSG((mintime > 0) && (maxtime / mintime <= UINT8_MAX)); + + /* Convert time to register value */ + uint8_t value = time / mintime; + + LOG_INF("Set downshift time to %u ms (reg value 0x%x)", time, value); + + int err = reg_write(dev, reg_addr, value); + if (err) { + LOG_ERR("Failed to change downshift time"); + } + + return err; +} + +/* set sampling rate in each mode (in ms) */ +static int set_sample_time(const struct device *dev, uint8_t reg_addr_lower, uint8_t reg_addr_upper, + uint32_t sample_time) { + /* Set sample time for the Rest1-Rest3 modes. + * Values above 0x09B0 will trigger internal watchdog reset. + */ + uint32_t maxtime = 0x9B0; + uint32_t mintime = 1; + + if ((sample_time > maxtime) || (sample_time < mintime)) { + LOG_WRN("Sample time %u out of range", sample_time); + return -EINVAL; + } + + LOG_INF("Set sample time to %u ms", sample_time); + + /* The sample time is (reg_value + 1) ms. */ + sample_time--; + uint8_t buf[2]; + + sys_put_le16((uint16_t)sample_time, buf); + + int err = reg_write(dev, reg_addr_lower, buf[0]); + + if (!err) { + err = reg_write(dev, reg_addr_upper, buf[1]); + } else { + LOG_ERR("Failed to change sample time"); + } + + return err; +} + +static int set_rest_modes(const struct device *dev, uint8_t reg_addr, bool enable) { + uint8_t value; + int err = reg_read(dev, reg_addr, &value); + + if (err) { + LOG_ERR("Failed to read Config2 register"); + return err; + } + + WRITE_BIT(value, PMW3360_REST_EN_POS, enable); + + LOG_INF("%sable rest modes", (enable) ? ("En") : ("Dis")); + err = reg_write(dev, reg_addr, value); + + if (err) { + LOG_ERR("Failed to set rest mode"); + } + + return err; +} + +static int pmw3360_async_init_fw_load_start(const struct device *dev) { + int err = 0; + + /* Read from registers 0x02-0x06 regardless of the motion pin state. */ + for (uint8_t reg = 0x02; (reg <= 0x06) && !err; reg++) { + uint8_t buf[1]; + err = reg_read(dev, reg, buf); + } + + if (err) { + LOG_ERR("Cannot read from data registers"); + return err; + } + + /* Write 0 to Rest_En bit of Config2 register to disable Rest mode. */ + err = reg_write(dev, PMW3360_REG_CONFIG2, 0x00); + if (err) { + LOG_ERR("Cannot disable REST mode"); + return err; + } + + /* Write 0x1D in SROM_enable register to initialize the operation */ + err = reg_write(dev, PMW3360_REG_SROM_ENABLE, 0x1D); + if (err) { + LOG_ERR("Cannot initialize SROM"); + return err; + } + + return err; +} + +static int pmw3360_async_init_fw_load_continue(const struct device *dev) { + int err; + + LOG_INF("Uploading optical sensor firmware..."); + + /* Write 0x18 to SROM_enable to start SROM download */ + err = reg_write(dev, PMW3360_REG_SROM_ENABLE, 0x18); + if (err) { + LOG_ERR("Cannot start SROM download"); + return err; + } + + /* Write SROM file into SROM_Load_Burst register. + * Data must start with SROM_Load_Burst address. + */ + err = burst_write(dev, PMW3360_REG_SROM_LOAD_BURST, pmw3360_firmware_data, + pmw3360_firmware_length); + if (err) { + LOG_ERR("Cannot write firmware to sensor"); + } + + return err; +} + +static int pmw3360_async_init_fw_load_verify(const struct device *dev) { + int err; + + /* Read the SROM_ID register to verify the firmware ID before any + * other register reads or writes + */ + + uint8_t fw_id; + err = reg_read(dev, PMW3360_REG_SROM_ID, &fw_id); + if (err) { + LOG_ERR("Cannot obtain firmware id"); + return err; + } + + LOG_DBG("Optical chip firmware ID: 0x%x ", fw_id); + if (fw_id != PMW3360_FIRMWARE_ID) { + LOG_ERR("Chip is not running from SROM!, got fw_id as 0x%x, the expected fw_id is 0x%x ", fw_id, PMW3360_FIRMWARE_ID); + return -EIO; + } + + uint8_t product_id; + err = reg_read(dev, PMW3360_REG_PRODUCT_ID, &product_id); + if (err) { + LOG_ERR("Cannot obtain product id"); + return err; + } + + if (product_id != PMW3360_PRODUCT_ID) { + LOG_ERR("Invalid product id!"); + return -EIO; + } + + /* Write 0x20 to Config2 register for wireless mouse design. + * This enables entering rest modes. + */ + err = reg_write(dev, PMW3360_REG_CONFIG2, 0x20); + if (err) { + LOG_ERR("Cannot enable REST modes"); + } + + return err; +} + +static void irq_handler(const struct device *gpiob, struct gpio_callback *cb, uint32_t pins) { + int err; + struct pixart_data *data = CONTAINER_OF(cb, struct pixart_data, irq_gpio_cb); + const struct device *dev = data->dev; + const struct pixart_config *config = dev->config; + + // disable the interrupt line first + err = gpio_pin_interrupt_configure_dt(&config->irq_gpio, GPIO_INT_DISABLE); + if (unlikely(err)) { + LOG_ERR("Cannot disable IRQ"); + k_panic(); + } + + // submit the real handler work + k_work_submit(&data->trigger_handler_work); +} + +static void trigger_handler(struct k_work *work) { + sensor_trigger_handler_t handler; + int err = 0; + struct pixart_data *data = CONTAINER_OF(work, struct pixart_data, trigger_handler_work); + const struct device *dev = data->dev; + const struct pixart_config *config = dev->config; + + // 1. the first lock period is used to procoss the trigger + // if data_ready_handler is non-NULL, otherwise do nothing + k_spinlock_key_t key = k_spin_lock(&data->lock); + + handler = data->data_ready_handler; + k_spin_unlock(&data->lock, key); + + if (!handler) { + return; + } + + handler(dev, data->trigger); + + // 2. the second lock period is used to resume the interrupt line + // if data_ready_handler is non-NULL, otherwise keep it inactive + key = k_spin_lock(&data->lock); + if (data->data_ready_handler) { + err = gpio_pin_interrupt_configure_dt(&config->irq_gpio, GPIO_INT_LEVEL_ACTIVE); + } + k_spin_unlock(&data->lock, key); + + if (unlikely(err)) { + LOG_ERR("Cannot re-enable IRQ"); + k_panic(); + } +} + +static int pmw3360_async_init_power_up(const struct device *dev) { + /* Reset sensor */ + + return reg_write(dev, PMW3360_REG_POWER_UP_RESET, PMW3360_POWERUP_CMD_RESET); +} + +static int pmw3360_async_init_configure(const struct device *dev) { + int err; + + err = set_cpi(dev, CONFIG_PMW3360_CPI); + + if (!err) { + err = set_downshift_time(dev, PMW3360_REG_RUN_DOWNSHIFT, + CONFIG_PMW3360_RUN_DOWNSHIFT_TIME_MS); + } + + if (!err) { + err = set_downshift_time(dev, PMW3360_REG_REST1_DOWNSHIFT, + CONFIG_PMW3360_REST1_DOWNSHIFT_TIME_MS); + } + + if (!err) { + err = set_downshift_time(dev, PMW3360_REG_REST2_DOWNSHIFT, + CONFIG_PMW3360_REST2_DOWNSHIFT_TIME_MS); + } + + return err; +} + +static void pmw3360_async_init(struct k_work *work) { + struct pixart_data *data = CONTAINER_OF(work, struct pixart_data, init_work); + const struct device *dev = data->dev; + + LOG_DBG("PMW3360 async init step %d", data->async_init_step); + + data->err = async_init_fn[data->async_init_step](dev); + if (data->err) { + LOG_ERR("PMW3360 initialization failed"); + } else { + data->async_init_step++; + + if (data->async_init_step == ASYNC_INIT_STEP_COUNT) { + data->ready = true; // sensor is ready to work + LOG_INF("PMW3360 initialized"); + } else { + k_work_schedule(&data->init_work, K_MSEC(async_init_delay[data->async_init_step])); + } + } +} + +static int pmw3360_init_irq(const struct device *dev) { + int err; + struct pixart_data *data = dev->data; + const struct pixart_config *config = dev->config; + + // check readiness of irq gpio pin + if (!device_is_ready(config->irq_gpio.port)) { + LOG_ERR("IRQ GPIO device not ready"); + return -ENODEV; + } + + // init the irq pin + err = gpio_pin_configure_dt(&config->irq_gpio, GPIO_INPUT); + if (err) { + LOG_ERR("Cannot configure IRQ GPIO"); + return err; + } + + // setup and add the irq callback associated + gpio_init_callback(&data->irq_gpio_cb, irq_handler, BIT(config->irq_gpio.pin)); + + err = gpio_add_callback(config->irq_gpio.port, &data->irq_gpio_cb); + if (err) { + LOG_ERR("Cannot add IRQ GPIO callback"); + } + + return err; +} + +static int pmw3360_init(const struct device *dev) { + struct pixart_data *data = dev->data; + const struct pixart_config *config = dev->config; + int err; + + // init device pointer + data->dev = dev; + + // init trigger handler work + k_work_init(&data->trigger_handler_work, trigger_handler); + + // check readiness of spi bus + if (!spi_is_ready(&config->bus)) { + LOG_ERR("SPI device not ready"); + return -ENODEV; + } + + // check readiness of cs gpio pin and init it to inactive + if (!device_is_ready(config->cs_gpio.port)) { + LOG_ERR("SPI CS device not ready"); + return -ENODEV; + } + + err = gpio_pin_configure_dt(&config->cs_gpio, GPIO_OUTPUT_INACTIVE); + if (err) { + LOG_ERR("Cannot configure SPI CS GPIO"); + return err; + } + + // init irq routine + err = pmw3360_init_irq(dev); + if (err) { + return err; + } + + // Setup delayable and non-blocking init jobs, including following steps: + // 1. power reset + // 2. clear motion registers + // 3. srom firmware download and checking + // 4. eable rest mode + // 5. set cpi and downshift time (not sample rate) + // The sensor is ready to work (i.e., data->ready=true after the above steps are finished) + k_work_init_delayable(&data->init_work, pmw3360_async_init); + + k_work_schedule(&data->init_work, K_MSEC(async_init_delay[data->async_init_step])); + + return err; +} + +static int pmw3360_sample_fetch(const struct device *dev, enum sensor_channel chan) { + struct pixart_data *data = dev->data; + uint8_t buf[PMW3360_BURST_SIZE]; + + if (unlikely(chan != SENSOR_CHAN_ALL)) { + return -ENOTSUP; + } + + if (unlikely(!data->ready)) { + LOG_DBG("Device is not initialized yet"); + return -EBUSY; + } + + int err = motion_burst_read(dev, buf, sizeof(buf)); + + if (!err) { + int16_t x = ((int16_t)sys_get_le16(&buf[PMW3360_DX_POS])) / CONFIG_PMW3360_CPI_DIVIDOR; + int16_t y = ((int16_t)sys_get_le16(&buf[PMW3360_DY_POS])) / CONFIG_PMW3360_CPI_DIVIDOR; + /* int16_t x = sys_get_le16(&buf[PMW3360_DX_POS]); */ + /* int16_t y = sys_get_le16(&buf[PMW3360_DY_POS]); */ + + if (IS_ENABLED(CONFIG_PMW3360_ORIENTATION_0)) { + data->x = -x; + data->y = y; + } else if (IS_ENABLED(CONFIG_PMW3360_ORIENTATION_90)) { + data->x = y; + data->y = -x; + } else if (IS_ENABLED(CONFIG_PMW3360_ORIENTATION_180)) { + data->x = x; + data->y = -y; + } else if (IS_ENABLED(CONFIG_PMW3360_ORIENTATION_270)) { + data->x = -y; + data->y = x; + } + } + + return err; +} + +static int pmw3360_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) { + struct pixart_data *data = dev->data; + + if (unlikely(!data->ready)) { + LOG_DBG("Device is not initialized yet"); + return -EBUSY; + } + + switch (chan) { + case SENSOR_CHAN_POS_DX: + val->val1 = data->x; + val->val2 = 0; + break; + + case SENSOR_CHAN_POS_DY: + val->val1 = data->y; + val->val2 = 0; + break; + + default: + return -ENOTSUP; + } + + return 0; +} + +/* Setup the callback for actual trigger handling */ +// handler could be NULL, in which case the effect is disabling the interrupt line +// Thus it has dual function: +// 1. set up a handler callback +// 2. set up a flag (i.e., data_ready_handler) to indicate resuming the interrput line or not +// This feature is useful to pass the resuming of the interrupt to application +static int pmw3360_trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) { + struct pixart_data *data = dev->data; + const struct pixart_config *config = dev->config; + int err; + + if (unlikely(trig->type != SENSOR_TRIG_DATA_READY)) { + return -ENOTSUP; + } + + if (unlikely(trig->chan != SENSOR_CHAN_ALL)) { + return -ENOTSUP; + } + + if (unlikely(!data->ready)) { + LOG_DBG("Device is not initialized yet"); + return -EBUSY; + } + + // spin lock is needed, so that the handler is not invoked before its pointer is assigned + // a valid value + k_spinlock_key_t key = k_spin_lock(&data->lock); + + // if non-NULL (a real handler defined), eanble the interrupt line + // otherwise, disable the interrupt line + if (handler) { + err = gpio_pin_interrupt_configure_dt(&config->irq_gpio, GPIO_INT_LEVEL_ACTIVE); + } else { + err = gpio_pin_interrupt_configure_dt(&config->irq_gpio, GPIO_INT_DISABLE); + } + + if (!err) { + data->data_ready_handler = handler; + } + + data->trigger = trig; + + k_spin_unlock(&data->lock, key); + + return err; +} + +static int pmw3360_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) { + struct pixart_data *data = dev->data; + int err; + + if (unlikely(chan != SENSOR_CHAN_ALL)) { + return -ENOTSUP; + } + + if (unlikely(!data->ready)) { + LOG_DBG("Device is not initialized yet"); + return -EBUSY; + } + + switch ((uint32_t)attr) { + case PMW3360_ATTR_CPI: + err = set_cpi(dev, PMW3360_SVALUE_TO_CPI(*val)); + break; + + case PMW3360_ATTR_REST_ENABLE: + err = set_rest_modes(dev, PMW3360_REG_CONFIG2, PMW3360_SVALUE_TO_BOOL(*val)); + break; + + case PMW3360_ATTR_RUN_DOWNSHIFT_TIME: + err = set_downshift_time(dev, PMW3360_REG_RUN_DOWNSHIFT, PMW3360_SVALUE_TO_TIME(*val)); + break; + + case PMW3360_ATTR_REST1_DOWNSHIFT_TIME: + err = set_downshift_time(dev, PMW3360_REG_REST1_DOWNSHIFT, PMW3360_SVALUE_TO_TIME(*val)); + break; + + case PMW3360_ATTR_REST2_DOWNSHIFT_TIME: + err = set_downshift_time(dev, PMW3360_REG_REST2_DOWNSHIFT, PMW3360_SVALUE_TO_TIME(*val)); + break; + + case PMW3360_ATTR_REST1_SAMPLE_TIME: + err = set_sample_time(dev, PMW3360_REG_REST1_RATE_LOWER, PMW3360_REG_REST1_RATE_UPPER, + PMW3360_SVALUE_TO_TIME(*val)); + break; + + case PMW3360_ATTR_REST2_SAMPLE_TIME: + err = set_sample_time(dev, PMW3360_REG_REST2_RATE_LOWER, PMW3360_REG_REST2_RATE_UPPER, + PMW3360_SVALUE_TO_TIME(*val)); + break; + + case PMW3360_ATTR_REST3_SAMPLE_TIME: + err = set_sample_time(dev, PMW3360_REG_REST3_RATE_LOWER, PMW3360_REG_REST3_RATE_UPPER, + PMW3360_SVALUE_TO_TIME(*val)); + break; + + default: + LOG_ERR("Unknown attribute"); + return -ENOTSUP; + } + + return err; +} + +static const struct sensor_driver_api pmw3360_driver_api = { + .sample_fetch = pmw3360_sample_fetch, + .channel_get = pmw3360_channel_get, + .trigger_set = pmw3360_trigger_set, + .attr_set = pmw3360_attr_set, +}; + +#define PMW3360_DEFINE(n) \ + static struct pixart_data data##n; \ + \ + static const struct pixart_config config##n = { \ + .irq_gpio = GPIO_DT_SPEC_INST_GET(n, irq_gpios), \ + .bus = \ + { \ + .bus = DEVICE_DT_GET(DT_INST_BUS(n)), \ + .config = \ + { \ + .frequency = DT_INST_PROP(n, spi_max_frequency), \ + .operation = \ + SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA, \ + .slave = DT_INST_REG_ADDR(n), \ + }, \ + }, \ + .cs_gpio = SPI_CS_GPIOS_DT_SPEC_GET(DT_DRV_INST(n)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, pmw3360_init, NULL, &data##n, &config##n, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &pmw3360_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(PMW3360_DEFINE) diff --git a/app/drivers/sensor/pixart/pmw3360/pmw3360.h b/app/drivers/sensor/pixart/pmw3360/pmw3360.h new file mode 100644 index 00000000000..46de5fc90ea --- /dev/null +++ b/app/drivers/sensor/pixart/pmw3360/pmw3360.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef ZEPHYR_INCLUDE_PMW3360_H_ +#define ZEPHYR_INCLUDE_PMW3360_H_ + +/** + * @file pmw3360.h + * + * @brief Header file for the pmw3360 driver. + */ + +#include "../pixart.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Sensor specific attributes of PMW3360. */ +enum pmw3360_attribute { + /** Sensor CPI for both X and Y axes. */ + PMW3360_ATTR_CPI = SENSOR_ATTR_PRIV_START, + + /** Enable or disable sleep modes. */ + PMW3360_ATTR_REST_ENABLE, + + /** Entering time from Run mode to REST1 mode [ms]. */ + PMW3360_ATTR_RUN_DOWNSHIFT_TIME, + + /** Entering time from REST1 mode to REST2 mode [ms]. */ + PMW3360_ATTR_REST1_DOWNSHIFT_TIME, + + /** Entering time from REST2 mode to REST3 mode [ms]. */ + PMW3360_ATTR_REST2_DOWNSHIFT_TIME, + + /** Sampling frequency time during REST1 mode [ms]. */ + PMW3360_ATTR_REST1_SAMPLE_TIME, + + /** Sampling frequency time during REST2 mode [ms]. */ + PMW3360_ATTR_REST2_SAMPLE_TIME, + + /** Sampling frequency time during REST3 mode [ms]. */ + PMW3360_ATTR_REST3_SAMPLE_TIME, +}; + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_PMW3360_H_ */ diff --git a/app/drivers/sensor/pixart/pmw3360/pmw3360_priv.c b/app/drivers/sensor/pixart/pmw3360/pmw3360_priv.c new file mode 100644 index 00000000000..8ed123d2dc3 --- /dev/null +++ b/app/drivers/sensor/pixart/pmw3360/pmw3360_priv.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/* +This SROM is provided "AS IS" by PixArt Imaging Inc., WITHOUT WARRANTY +OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL PIXART +IMAGING INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THIS +SROM OR THE USE OR OTHER DEALINGS IN THIS SROM. +*/ + +#include +#include + +const size_t pmw3360_firmware_length = 4094; + +/* Firmware "0x04" */ +const uint8_t pmw3360_firmware_data[] = { +0x01, 0x04, 0x8e, 0x96, 0x6e, 0x77, 0x3e, 0xfe, 0x7e, 0x5f, 0x1d, 0xb8, 0xf2, 0x66, 0x4e, +0xff, 0x5d, 0x19, 0xb0, 0xc2, 0x04, 0x69, 0x54, 0x2a, 0xd6, 0x2e, 0xbf, 0xdd, 0x19, 0xb0, +0xc3, 0xe5, 0x29, 0xb1, 0xe0, 0x23, 0xa5, 0xa9, 0xb1, 0xc1, 0x00, 0x82, 0x67, 0x4c, 0x1a, +0x97, 0x8d, 0x79, 0x51, 0x20, 0xc7, 0x06, 0x8e, 0x7c, 0x7c, 0x7a, 0x76, 0x4f, 0xfd, 0x59, +0x30, 0xe2, 0x46, 0x0e, 0x9e, 0xbe, 0xdf, 0x1d, 0x99, 0x91, 0xa0, 0xa5, 0xa1, 0xa9, 0xd0, +0x22, 0xc6, 0xef, 0x5c, 0x1b, 0x95, 0x89, 0x90, 0xa2, 0xa7, 0xcc, 0xfb, 0x55, 0x28, 0xb3, +0xe4, 0x4a, 0xf7, 0x6c, 0x3b, 0xf4, 0x6a, 0x56, 0x2e, 0xde, 0x1f, 0x9d, 0xb8, 0xd3, 0x05, +0x88, 0x92, 0xa6, 0xce, 0x1e, 0xbe, 0xdf, 0x1d, 0x99, 0xb0, 0xe2, 0x46, 0xef, 0x5c, 0x07, +0x11, 0x5d, 0x98, 0x0b, 0x9d, 0x94, 0x97, 0xee, 0x4e, 0x45, 0x33, 0x6b, 0x44, 0xc7, 0x29, +0x56, 0x27, 0x30, 0xc6, 0xa7, 0xd5, 0xf2, 0x56, 0xdf, 0xb4, 0x38, 0x62, 0xcb, 0xa0, 0xb6, +0xe3, 0x0f, 0x84, 0x06, 0x24, 0x05, 0x65, 0x6f, 0x76, 0x89, 0xb5, 0x77, 0x41, 0x27, 0x82, +0x66, 0x65, 0x82, 0xcc, 0xd5, 0xe6, 0x20, 0xd5, 0x27, 0x17, 0xc5, 0xf8, 0x03, 0x23, 0x7c, +0x5f, 0x64, 0xa5, 0x1d, 0xc1, 0xd6, 0x36, 0xcb, 0x4c, 0xd4, 0xdb, 0x66, 0xd7, 0x8b, 0xb1, +0x99, 0x7e, 0x6f, 0x4c, 0x36, 0x40, 0x06, 0xd6, 0xeb, 0xd7, 0xa2, 0xe4, 0xf4, 0x95, 0x51, +0x5a, 0x54, 0x96, 0xd5, 0x53, 0x44, 0xd7, 0x8c, 0xe0, 0xb9, 0x40, 0x68, 0xd2, 0x18, 0xe9, +0xdd, 0x9a, 0x23, 0x92, 0x48, 0xee, 0x7f, 0x43, 0xaf, 0xea, 0x77, 0x38, 0x84, 0x8c, 0x0a, +0x72, 0xaf, 0x69, 0xf8, 0xdd, 0xf1, 0x24, 0x83, 0xa3, 0xf8, 0x4a, 0xbf, 0xf5, 0x94, 0x13, +0xdb, 0xbb, 0xd8, 0xb4, 0xb3, 0xa0, 0xfb, 0x45, 0x50, 0x60, 0x30, 0x59, 0x12, 0x31, 0x71, +0xa2, 0xd3, 0x13, 0xe7, 0xfa, 0xe7, 0xce, 0x0f, 0x63, 0x15, 0x0b, 0x6b, 0x94, 0xbb, 0x37, +0x83, 0x26, 0x05, 0x9d, 0xfb, 0x46, 0x92, 0xfc, 0x0a, 0x15, 0xd1, 0x0d, 0x73, 0x92, 0xd6, +0x8c, 0x1b, 0x8c, 0xb8, 0x55, 0x8a, 0xce, 0xbd, 0xfe, 0x8e, 0xfc, 0xed, 0x09, 0x12, 0x83, +0x91, 0x82, 0x51, 0x31, 0x23, 0xfb, 0xb4, 0x0c, 0x76, 0xad, 0x7c, 0xd9, 0xb4, 0x4b, 0xb2, +0x67, 0x14, 0x09, 0x9c, 0x7f, 0x0c, 0x18, 0xba, 0x3b, 0xd6, 0x8e, 0x14, 0x2a, 0xe4, 0x1b, +0x52, 0x9f, 0x2b, 0x7d, 0xe1, 0xfb, 0x6a, 0x33, 0x02, 0xfa, 0xac, 0x5a, 0xf2, 0x3e, 0x88, +0x7e, 0xae, 0xd1, 0xf3, 0x78, 0xe8, 0x05, 0xd1, 0xe3, 0xdc, 0x21, 0xf6, 0xe1, 0x9a, 0xbd, +0x17, 0x0e, 0xd9, 0x46, 0x9b, 0x88, 0x03, 0xea, 0xf6, 0x66, 0xbe, 0x0e, 0x1b, 0x50, 0x49, +0x96, 0x40, 0x97, 0xf1, 0xf1, 0xe4, 0x80, 0xa6, 0x6e, 0xe8, 0x77, 0x34, 0xbf, 0x29, 0x40, +0x44, 0xc2, 0xff, 0x4e, 0x98, 0xd3, 0x9c, 0xa3, 0x32, 0x2b, 0x76, 0x51, 0x04, 0x09, 0xe7, +0xa9, 0xd1, 0xa6, 0x32, 0xb1, 0x23, 0x53, 0xe2, 0x47, 0xab, 0xd6, 0xf5, 0x69, 0x5c, 0x3e, +0x5f, 0xfa, 0xae, 0x45, 0x20, 0xe5, 0xd2, 0x44, 0xff, 0x39, 0x32, 0x6d, 0xfd, 0x27, 0x57, +0x5c, 0xfd, 0xf0, 0xde, 0xc1, 0xb5, 0x99, 0xe5, 0xf5, 0x1c, 0x77, 0x01, 0x75, 0xc5, 0x6d, +0x58, 0x92, 0xf2, 0xb2, 0x47, 0x00, 0x01, 0x26, 0x96, 0x7a, 0x30, 0xff, 0xb7, 0xf0, 0xef, +0x77, 0xc1, 0x8a, 0x5d, 0xdc, 0xc0, 0xd1, 0x29, 0x30, 0x1e, 0x77, 0x38, 0x7a, 0x94, 0xf1, +0xb8, 0x7a, 0x7e, 0xef, 0xa4, 0xd1, 0xac, 0x31, 0x4a, 0xf2, 0x5d, 0x64, 0x3d, 0xb2, 0xe2, +0xf0, 0x08, 0x99, 0xfc, 0x70, 0xee, 0x24, 0xa7, 0x7e, 0xee, 0x1e, 0x20, 0x69, 0x7d, 0x44, +0xbf, 0x87, 0x42, 0xdf, 0x88, 0x3b, 0x0c, 0xda, 0x42, 0xc9, 0x04, 0xf9, 0x45, 0x50, 0xfc, +0x83, 0x8f, 0x11, 0x6a, 0x72, 0xbc, 0x99, 0x95, 0xf0, 0xac, 0x3d, 0xa7, 0x3b, 0xcd, 0x1c, +0xe2, 0x88, 0x79, 0x37, 0x11, 0x5f, 0x39, 0x89, 0x95, 0x0a, 0x16, 0x84, 0x7a, 0xf6, 0x8a, +0xa4, 0x28, 0xe4, 0xed, 0x83, 0x80, 0x3b, 0xb1, 0x23, 0xa5, 0x03, 0x10, 0xf4, 0x66, 0xea, +0xbb, 0x0c, 0x0f, 0xc5, 0xec, 0x6c, 0x69, 0xc5, 0xd3, 0x24, 0xab, 0xd4, 0x2a, 0xb7, 0x99, +0x88, 0x76, 0x08, 0xa0, 0xa8, 0x95, 0x7c, 0xd8, 0x38, 0x6d, 0xcd, 0x59, 0x02, 0x51, 0x4b, +0xf1, 0xb5, 0x2b, 0x50, 0xe3, 0xb6, 0xbd, 0xd0, 0x72, 0xcf, 0x9e, 0xfd, 0x6e, 0xbb, 0x44, +0xc8, 0x24, 0x8a, 0x77, 0x18, 0x8a, 0x13, 0x06, 0xef, 0x97, 0x7d, 0xfa, 0x81, 0xf0, 0x31, +0xe6, 0xfa, 0x77, 0xed, 0x31, 0x06, 0x31, 0x5b, 0x54, 0x8a, 0x9f, 0x30, 0x68, 0xdb, 0xe2, +0x40, 0xf8, 0x4e, 0x73, 0xfa, 0xab, 0x74, 0x8b, 0x10, 0x58, 0x13, 0xdc, 0xd2, 0xe6, 0x78, +0xd1, 0x32, 0x2e, 0x8a, 0x9f, 0x2c, 0x58, 0x06, 0x48, 0x27, 0xc5, 0xa9, 0x5e, 0x81, 0x47, +0x89, 0x46, 0x21, 0x91, 0x03, 0x70, 0xa4, 0x3e, 0x88, 0x9c, 0xda, 0x33, 0x0a, 0xce, 0xbc, +0x8b, 0x8e, 0xcf, 0x9f, 0xd3, 0x71, 0x80, 0x43, 0xcf, 0x6b, 0xa9, 0x51, 0x83, 0x76, 0x30, +0x82, 0xc5, 0x6a, 0x85, 0x39, 0x11, 0x50, 0x1a, 0x82, 0xdc, 0x1e, 0x1c, 0xd5, 0x7d, 0xa9, +0x71, 0x99, 0x33, 0x47, 0x19, 0x97, 0xb3, 0x5a, 0xb1, 0xdf, 0xed, 0xa4, 0xf2, 0xe6, 0x26, +0x84, 0xa2, 0x28, 0x9a, 0x9e, 0xdf, 0xa6, 0x6a, 0xf4, 0xd6, 0xfc, 0x2e, 0x5b, 0x9d, 0x1a, +0x2a, 0x27, 0x68, 0xfb, 0xc1, 0x83, 0x21, 0x4b, 0x90, 0xe0, 0x36, 0xdd, 0x5b, 0x31, 0x42, +0x55, 0xa0, 0x13, 0xf7, 0xd0, 0x89, 0x53, 0x71, 0x99, 0x57, 0x09, 0x29, 0xc5, 0xf3, 0x21, +0xf8, 0x37, 0x2f, 0x40, 0xf3, 0xd4, 0xaf, 0x16, 0x08, 0x36, 0x02, 0xfc, 0x77, 0xc5, 0x8b, +0x04, 0x90, 0x56, 0xb9, 0xc9, 0x67, 0x9a, 0x99, 0xe8, 0x00, 0xd3, 0x86, 0xff, 0x97, 0x2d, +0x08, 0xe9, 0xb7, 0xb3, 0x91, 0xbc, 0xdf, 0x45, 0xc6, 0xed, 0x0f, 0x8c, 0x4c, 0x1e, 0xe6, +0x5b, 0x6e, 0x38, 0x30, 0xe4, 0xaa, 0xe3, 0x95, 0xde, 0xb9, 0xe4, 0x9a, 0xf5, 0xb2, 0x55, +0x9a, 0x87, 0x9b, 0xf6, 0x6a, 0xb2, 0xf2, 0x77, 0x9a, 0x31, 0xf4, 0x7a, 0x31, 0xd1, 0x1d, +0x04, 0xc0, 0x7c, 0x32, 0xa2, 0x9e, 0x9a, 0xf5, 0x62, 0xf8, 0x27, 0x8d, 0xbf, 0x51, 0xff, +0xd3, 0xdf, 0x64, 0x37, 0x3f, 0x2a, 0x6f, 0x76, 0x3a, 0x7d, 0x77, 0x06, 0x9e, 0x77, 0x7f, +0x5e, 0xeb, 0x32, 0x51, 0xf9, 0x16, 0x66, 0x9a, 0x09, 0xf3, 0xb0, 0x08, 0xa4, 0x70, 0x96, +0x46, 0x30, 0xff, 0xda, 0x4f, 0xe9, 0x1b, 0xed, 0x8d, 0xf8, 0x74, 0x1f, 0x31, 0x92, 0xb3, +0x73, 0x17, 0x36, 0xdb, 0x91, 0x30, 0xd6, 0x88, 0x55, 0x6b, 0x34, 0x77, 0x87, 0x7a, 0xe7, +0xee, 0x06, 0xc6, 0x1c, 0x8c, 0x19, 0x0c, 0x48, 0x46, 0x23, 0x5e, 0x9c, 0x07, 0x5c, 0xbf, +0xb4, 0x7e, 0xd6, 0x4f, 0x74, 0x9c, 0xe2, 0xc5, 0x50, 0x8b, 0xc5, 0x8b, 0x15, 0x90, 0x60, +0x62, 0x57, 0x29, 0xd0, 0x13, 0x43, 0xa1, 0x80, 0x88, 0x91, 0x00, 0x44, 0xc7, 0x4d, 0x19, +0x86, 0xcc, 0x2f, 0x2a, 0x75, 0x5a, 0xfc, 0xeb, 0x97, 0x2a, 0x70, 0xe3, 0x78, 0xd8, 0x91, +0xb0, 0x4f, 0x99, 0x07, 0xa3, 0x95, 0xea, 0x24, 0x21, 0xd5, 0xde, 0x51, 0x20, 0x93, 0x27, +0x0a, 0x30, 0x73, 0xa8, 0xff, 0x8a, 0x97, 0xe9, 0xa7, 0x6a, 0x8e, 0x0d, 0xe8, 0xf0, 0xdf, +0xec, 0xea, 0xb4, 0x6c, 0x1d, 0x39, 0x2a, 0x62, 0x2d, 0x3d, 0x5a, 0x8b, 0x65, 0xf8, 0x90, +0x05, 0x2e, 0x7e, 0x91, 0x2c, 0x78, 0xef, 0x8e, 0x7a, 0xc1, 0x2f, 0xac, 0x78, 0xee, 0xaf, +0x28, 0x45, 0x06, 0x4c, 0x26, 0xaf, 0x3b, 0xa2, 0xdb, 0xa3, 0x93, 0x06, 0xb5, 0x3c, 0xa5, +0xd8, 0xee, 0x8f, 0xaf, 0x25, 0xcc, 0x3f, 0x85, 0x68, 0x48, 0xa9, 0x62, 0xcc, 0x97, 0x8f, +0x7f, 0x2a, 0xea, 0xe0, 0x15, 0x0a, 0xad, 0x62, 0x07, 0xbd, 0x45, 0xf8, 0x41, 0xd8, 0x36, +0xcb, 0x4c, 0xdb, 0x6e, 0xe6, 0x3a, 0xe7, 0xda, 0x15, 0xe9, 0x29, 0x1e, 0x12, 0x10, 0xa0, +0x14, 0x2c, 0x0e, 0x3d, 0xf4, 0xbf, 0x39, 0x41, 0x92, 0x75, 0x0b, 0x25, 0x7b, 0xa3, 0xce, +0x39, 0x9c, 0x15, 0x64, 0xc8, 0xfa, 0x3d, 0xef, 0x73, 0x27, 0xfe, 0x26, 0x2e, 0xce, 0xda, +0x6e, 0xfd, 0x71, 0x8e, 0xdd, 0xfe, 0x76, 0xee, 0xdc, 0x12, 0x5c, 0x02, 0xc5, 0x3a, 0x4e, +0x4e, 0x4f, 0xbf, 0xca, 0x40, 0x15, 0xc7, 0x6e, 0x8d, 0x41, 0xf1, 0x10, 0xe0, 0x4f, 0x7e, +0x97, 0x7f, 0x1c, 0xae, 0x47, 0x8e, 0x6b, 0xb1, 0x25, 0x31, 0xb0, 0x73, 0xc7, 0x1b, 0x97, +0x79, 0xf9, 0x80, 0xd3, 0x66, 0x22, 0x30, 0x07, 0x74, 0x1e, 0xe4, 0xd0, 0x80, 0x21, 0xd6, +0xee, 0x6b, 0x6c, 0x4f, 0xbf, 0xf5, 0xb7, 0xd9, 0x09, 0x87, 0x2f, 0xa9, 0x14, 0xbe, 0x27, +0xd9, 0x72, 0x50, 0x01, 0xd4, 0x13, 0x73, 0xa6, 0xa7, 0x51, 0x02, 0x75, 0x25, 0xe1, 0xb3, +0x45, 0x34, 0x7d, 0xa8, 0x8e, 0xeb, 0xf3, 0x16, 0x49, 0xcb, 0x4f, 0x8c, 0xa1, 0xb9, 0x36, +0x85, 0x39, 0x75, 0x5d, 0x08, 0x00, 0xae, 0xeb, 0xf6, 0xea, 0xd7, 0x13, 0x3a, 0x21, 0x5a, +0x5f, 0x30, 0x84, 0x52, 0x26, 0x95, 0xc9, 0x14, 0xf2, 0x57, 0x55, 0x6b, 0xb1, 0x10, 0xc2, +0xe1, 0xbd, 0x3b, 0x51, 0xc0, 0xb7, 0x55, 0x4c, 0x71, 0x12, 0x26, 0xc7, 0x0d, 0xf9, 0x51, +0xa4, 0x38, 0x02, 0x05, 0x7f, 0xb8, 0xf1, 0x72, 0x4b, 0xbf, 0x71, 0x89, 0x14, 0xf3, 0x77, +0x38, 0xd9, 0x71, 0x24, 0xf3, 0x00, 0x11, 0xa1, 0xd8, 0xd4, 0x69, 0x27, 0x08, 0x37, 0x35, +0xc9, 0x11, 0x9d, 0x90, 0x1c, 0x0e, 0xe7, 0x1c, 0xff, 0x2d, 0x1e, 0xe8, 0x92, 0xe1, 0x18, +0x10, 0x95, 0x7c, 0xe0, 0x80, 0xf4, 0x96, 0x43, 0x21, 0xf9, 0x75, 0x21, 0x64, 0x38, 0xdd, +0x9f, 0x1e, 0x95, 0x16, 0xda, 0x56, 0x1d, 0x4f, 0x9a, 0x53, 0xb2, 0xe2, 0xe4, 0x18, 0xcb, +0x6b, 0x1a, 0x65, 0xeb, 0x56, 0xc6, 0x3b, 0xe5, 0xfe, 0xd8, 0x26, 0x3f, 0x3a, 0x84, 0x59, +0x72, 0x66, 0xa2, 0xf3, 0x75, 0xff, 0xfb, 0x60, 0xb3, 0x22, 0xad, 0x3f, 0x2d, 0x6b, 0xf9, +0xeb, 0xea, 0x05, 0x7c, 0xd8, 0x8f, 0x6d, 0x2c, 0x98, 0x9e, 0x2b, 0x93, 0xf1, 0x5e, 0x46, +0xf0, 0x87, 0x49, 0x29, 0x73, 0x68, 0xd7, 0x7f, 0xf9, 0xf0, 0xe5, 0x7d, 0xdb, 0x1d, 0x75, +0x19, 0xf3, 0xc4, 0x58, 0x9b, 0x17, 0x88, 0xa8, 0x92, 0xe0, 0xbe, 0xbd, 0x8b, 0x1d, 0x8d, +0x9f, 0x56, 0x76, 0xad, 0xaf, 0x29, 0xe2, 0xd9, 0xd5, 0x52, 0xf6, 0xb5, 0x56, 0x35, 0x57, +0x3a, 0xc8, 0xe1, 0x56, 0x43, 0x19, 0x94, 0xd3, 0x04, 0x9b, 0x6d, 0x35, 0xd8, 0x0b, 0x5f, +0x4d, 0x19, 0x8e, 0xec, 0xfa, 0x64, 0x91, 0x0a, 0x72, 0x20, 0x2b, 0xbc, 0x1a, 0x4a, 0xfe, +0x8b, 0xfd, 0xbb, 0xed, 0x1b, 0x23, 0xea, 0xad, 0x72, 0x82, 0xa1, 0x29, 0x99, 0x71, 0xbd, +0xf0, 0x95, 0xc1, 0x03, 0xdd, 0x7b, 0xc2, 0xb2, 0x3c, 0x28, 0x54, 0xd3, 0x68, 0xa4, 0x72, +0xc8, 0x66, 0x96, 0xe0, 0xd1, 0xd8, 0x7f, 0xf8, 0xd1, 0x26, 0x2b, 0xf7, 0xad, 0xba, 0x55, +0xca, 0x15, 0xb9, 0x32, 0xc3, 0xe5, 0x88, 0x97, 0x8e, 0x5c, 0xfb, 0x92, 0x25, 0x8b, 0xbf, +0xa2, 0x45, 0x55, 0x7a, 0xa7, 0x6f, 0x8b, 0x57, 0x5b, 0xcf, 0x0e, 0xcb, 0x1d, 0xfb, 0x20, +0x82, 0x77, 0xa8, 0x8c, 0xcc, 0x16, 0xce, 0x1d, 0xfa, 0xde, 0xcc, 0x0b, 0x62, 0xfe, 0xcc, +0xe1, 0xb7, 0xf0, 0xc3, 0x81, 0x64, 0x73, 0x40, 0xa0, 0xc2, 0x4d, 0x89, 0x11, 0x75, 0x33, +0x55, 0x33, 0x8d, 0xe8, 0x4a, 0xfd, 0xea, 0x6e, 0x30, 0x0b, 0xd7, 0x31, 0x2c, 0xde, 0x47, +0xe3, 0xbf, 0xf8, 0x55, 0x42, 0xe2, 0x7f, 0x59, 0xe5, 0x17, 0xef, 0x99, 0x34, 0x69, 0x91, +0xb1, 0x23, 0x8e, 0x20, 0x87, 0x2d, 0xa8, 0xfe, 0xd5, 0x8a, 0xf3, 0x84, 0x3a, 0xf0, 0x37, +0xe4, 0x09, 0x00, 0x54, 0xee, 0x67, 0x49, 0x93, 0xe4, 0x81, 0x70, 0xe3, 0x90, 0x4d, 0xef, +0xfe, 0x41, 0xb7, 0x99, 0x7b, 0xc1, 0x83, 0xba, 0x62, 0x12, 0x6f, 0x7d, 0xde, 0x6b, 0xaf, +0xda, 0x16, 0xf9, 0x55, 0x51, 0xee, 0xa6, 0x0c, 0x2b, 0x02, 0xa3, 0xfd, 0x8d, 0xfb, 0x30, +0x17, 0xe4, 0x6f, 0xdf, 0x36, 0x71, 0xc4, 0xca, 0x87, 0x25, 0x48, 0xb0, 0x47, 0xec, 0xea, +0xb4, 0xbf, 0xa5, 0x4d, 0x9b, 0x9f, 0x02, 0x93, 0xc4, 0xe3, 0xe4, 0xe8, 0x42, 0x2d, 0x68, +0x81, 0x15, 0x0a, 0xeb, 0x84, 0x5b, 0xd6, 0xa8, 0x74, 0xfb, 0x7d, 0x1d, 0xcb, 0x2c, 0xda, +0x46, 0x2a, 0x76, 0x62, 0xce, 0xbc, 0x5c, 0x9e, 0x8b, 0xe7, 0xcf, 0xbe, 0x78, 0xf5, 0x7c, +0xeb, 0xb3, 0x3a, 0x9c, 0xaa, 0x6f, 0xcc, 0x72, 0xd1, 0x59, 0xf2, 0x11, 0x23, 0xd6, 0x3f, +0x48, 0xd1, 0xb7, 0xce, 0xb0, 0xbf, 0xcb, 0xea, 0x80, 0xde, 0x57, 0xd4, 0x5e, 0x97, 0x2f, +0x75, 0xd1, 0x50, 0x8e, 0x80, 0x2c, 0x66, 0x79, 0xbf, 0x72, 0x4b, 0xbd, 0x8a, 0x81, 0x6c, +0xd3, 0xe1, 0x01, 0xdc, 0xd2, 0x15, 0x26, 0xc5, 0x36, 0xda, 0x2c, 0x1a, 0xc0, 0x27, 0x94, +0xed, 0xb7, 0x9b, 0x85, 0x0b, 0x5e, 0x80, 0x97, 0xc5, 0xec, 0x4f, 0xec, 0x88, 0x5d, 0x50, +0x07, 0x35, 0x47, 0xdc, 0x0b, 0x3b, 0x3d, 0xdd, 0x60, 0xaf, 0xa8, 0x5d, 0x81, 0x38, 0x24, +0x25, 0x5d, 0x5c, 0x15, 0xd1, 0xde, 0xb3, 0xab, 0xec, 0x05, 0x69, 0xef, 0x83, 0xed, 0x57, +0x54, 0xb8, 0x64, 0x64, 0x11, 0x16, 0x32, 0x69, 0xda, 0x9f, 0x2d, 0x7f, 0x36, 0xbb, 0x44, +0x5a, 0x34, 0xe8, 0x7f, 0xbf, 0x03, 0xeb, 0x00, 0x7f, 0x59, 0x68, 0x22, 0x79, 0xcf, 0x73, +0x6c, 0x2c, 0x29, 0xa7, 0xa1, 0x5f, 0x38, 0xa1, 0x1d, 0xf0, 0x20, 0x53, 0xe0, 0x1a, 0x63, +0x14, 0x58, 0x71, 0x10, 0xaa, 0x08, 0x0c, 0x3e, 0x16, 0x1a, 0x60, 0x22, 0x82, 0x7f, 0xba, +0xa4, 0x43, 0xa0, 0xd0, 0xac, 0x1b, 0xd5, 0x6b, 0x64, 0xb5, 0x14, 0x93, 0x31, 0x9e, 0x53, +0x50, 0xd0, 0x57, 0x66, 0xee, 0x5a, 0x4f, 0xfb, 0x03, 0x2a, 0x69, 0x58, 0x76, 0xf1, 0x83, +0xf7, 0x4e, 0xba, 0x8c, 0x42, 0x06, 0x60, 0x5d, 0x6d, 0xce, 0x60, 0x88, 0xae, 0xa4, 0xc3, +0xf1, 0x03, 0xa5, 0x4b, 0x98, 0xa1, 0xff, 0x67, 0xe1, 0xac, 0xa2, 0xb8, 0x62, 0xd7, 0x6f, +0xa0, 0x31, 0xb4, 0xd2, 0x77, 0xaf, 0x21, 0x10, 0x06, 0xc6, 0x9a, 0xff, 0x1d, 0x09, 0x17, +0x0e, 0x5f, 0xf1, 0xaa, 0x54, 0x34, 0x4b, 0x45, 0x8a, 0x87, 0x63, 0xa6, 0xdc, 0xf9, 0x24, +0x30, 0x67, 0xc6, 0xb2, 0xd6, 0x61, 0x33, 0x69, 0xee, 0x50, 0x61, 0x57, 0x28, 0xe7, 0x7e, +0xee, 0xec, 0x3a, 0x5a, 0x73, 0x4e, 0xa8, 0x8d, 0xe4, 0x18, 0xea, 0xec, 0x41, 0x64, 0xc8, +0xe2, 0xe8, 0x66, 0xb6, 0x2d, 0xb6, 0xfb, 0x6a, 0x6c, 0x16, 0xb3, 0xdd, 0x46, 0x43, 0xb9, +0x73, 0x00, 0x6a, 0x71, 0xed, 0x4e, 0x9d, 0x25, 0x1a, 0xc3, 0x3c, 0x4a, 0x95, 0x15, 0x99, +0x35, 0x81, 0x14, 0x02, 0xd6, 0x98, 0x9b, 0xec, 0xd8, 0x23, 0x3b, 0x84, 0x29, 0xaf, 0x0c, +0x99, 0x83, 0xa6, 0x9a, 0x34, 0x4f, 0xfa, 0xe8, 0xd0, 0x3c, 0x4b, 0xd0, 0xfb, 0xb6, 0x68, +0xb8, 0x9e, 0x8f, 0xcd, 0xf7, 0x60, 0x2d, 0x7a, 0x22, 0xe5, 0x7d, 0xab, 0x65, 0x1b, 0x95, +0xa7, 0xa8, 0x7f, 0xb6, 0x77, 0x47, 0x7b, 0x5f, 0x8b, 0x12, 0x72, 0xd0, 0xd4, 0x91, 0xef, +0xde, 0x19, 0x50, 0x3c, 0xa7, 0x8b, 0xc4, 0xa9, 0xb3, 0x23, 0xcb, 0x76, 0xe6, 0x81, 0xf0, +0xc1, 0x04, 0x8f, 0xa3, 0xb8, 0x54, 0x5b, 0x97, 0xac, 0x19, 0xff, 0x3f, 0x55, 0x27, 0x2f, +0xe0, 0x1d, 0x42, 0x9b, 0x57, 0xfc, 0x4b, 0x4e, 0x0f, 0xce, 0x98, 0xa9, 0x43, 0x57, 0x03, +0xbd, 0xe7, 0xc8, 0x94, 0xdf, 0x6e, 0x36, 0x73, 0x32, 0xb4, 0xef, 0x2e, 0x85, 0x7a, 0x6e, +0xfc, 0x6c, 0x18, 0x82, 0x75, 0x35, 0x90, 0x07, 0xf3, 0xe4, 0x9f, 0x3e, 0xdc, 0x68, 0xf3, +0xb5, 0xf3, 0x19, 0x80, 0x92, 0x06, 0x99, 0xa2, 0xe8, 0x6f, 0xff, 0x2e, 0x7f, 0xae, 0x42, +0xa4, 0x5f, 0xfb, 0xd4, 0x0e, 0x81, 0x2b, 0xc3, 0x04, 0xff, 0x2b, 0xb3, 0x74, 0x4e, 0x36, +0x5b, 0x9c, 0x15, 0x00, 0xc6, 0x47, 0x2b, 0xe8, 0x8b, 0x3d, 0xf1, 0x9c, 0x03, 0x9a, 0x58, +0x7f, 0x9b, 0x9c, 0xbf, 0x85, 0x49, 0x79, 0x35, 0x2e, 0x56, 0x7b, 0x41, 0x14, 0x39, 0x47, +0x83, 0x26, 0xaa, 0x07, 0x89, 0x98, 0x11, 0x1b, 0x86, 0xe7, 0x73, 0x7a, 0xd8, 0x7d, 0x78, +0x61, 0x53, 0xe9, 0x79, 0xf5, 0x36, 0x8d, 0x44, 0x92, 0x84, 0xf9, 0x13, 0x50, 0x58, 0x3b, +0xa4, 0x6a, 0x36, 0x65, 0x49, 0x8e, 0x3c, 0x0e, 0xf1, 0x6f, 0xd2, 0x84, 0xc4, 0x7e, 0x8e, +0x3f, 0x39, 0xae, 0x7c, 0x84, 0xf1, 0x63, 0x37, 0x8e, 0x3c, 0xcc, 0x3e, 0x44, 0x81, 0x45, +0xf1, 0x4b, 0xb9, 0xed, 0x6b, 0x36, 0x5d, 0xbb, 0x20, 0x60, 0x1a, 0x0f, 0xa3, 0xaa, 0x55, +0x77, 0x3a, 0xa9, 0xae, 0x37, 0x4d, 0xba, 0xb8, 0x86, 0x6b, 0xbc, 0x08, 0x50, 0xf6, 0xcc, +0xa4, 0xbd, 0x1d, 0x40, 0x72, 0xa5, 0x86, 0xfa, 0xe2, 0x10, 0xae, 0x3d, 0x58, 0x4b, 0x97, +0xf3, 0x43, 0x74, 0xa9, 0x9e, 0xeb, 0x21, 0xb7, 0x01, 0xa4, 0x86, 0x93, 0x97, 0xee, 0x2f, +0x4f, 0x3b, 0x86, 0xa1, 0x41, 0x6f, 0x41, 0x26, 0x90, 0x78, 0x5c, 0x7f, 0x30, 0x38, 0x4b, +0x3f, 0xaa, 0xec, 0xed, 0x5c, 0x6f, 0x0e, 0xad, 0x43, 0x87, 0xfd, 0x93, 0x35, 0xe6, 0x01, +0xef, 0x41, 0x26, 0x90, 0x99, 0x9e, 0xfb, 0x19, 0x5b, 0xad, 0xd2, 0x91, 0x8a, 0xe0, 0x46, +0xaf, 0x65, 0xfa, 0x4f, 0x84, 0xc1, 0xa1, 0x2d, 0xcf, 0x45, 0x8b, 0xd3, 0x85, 0x50, 0x55, +0x7c, 0xf9, 0x67, 0x88, 0xd4, 0x4e, 0xe9, 0xd7, 0x6b, 0x61, 0x54, 0xa1, 0xa4, 0xa6, 0xa2, +0xc2, 0xbf, 0x30, 0x9c, 0x40, 0x9f, 0x5f, 0xd7, 0x69, 0x2b, 0x24, 0x82, 0x5e, 0xd9, 0xd6, +0xa7, 0x12, 0x54, 0x1a, 0xf7, 0x55, 0x9f, 0x76, 0x50, 0xa9, 0x95, 0x84, 0xe6, 0x6b, 0x6d, +0xb5, 0x96, 0x54, 0xd6, 0xcd, 0xb3, 0xa1, 0x9b, 0x46, 0xa7, 0x94, 0x4d, 0xc4, 0x94, 0xb4, +0x98, 0xe3, 0xe1, 0xe2, 0x34, 0xd5, 0x33, 0x16, 0x07, 0x54, 0xcd, 0xb7, 0x77, 0x53, 0xdb, +0x4f, 0x4d, 0x46, 0x9d, 0xe9, 0xd4, 0x9c, 0x8a, 0x36, 0xb6, 0xb8, 0x38, 0x26, 0x6c, 0x0e, +0xff, 0x9c, 0x1b, 0x43, 0x8b, 0x80, 0xcc, 0xb9, 0x3d, 0xda, 0xc7, 0xf1, 0x8a, 0xf2, 0x6d, +0xb8, 0xd7, 0x74, 0x2f, 0x7e, 0x1e, 0xb7, 0xd3, 0x4a, 0xb4, 0xac, 0xfc, 0x79, 0x48, 0x6c, +0xbc, 0x96, 0xb6, 0x94, 0x46, 0x57, 0x2d, 0xb0, 0xa3, 0xfc, 0x1e, 0xb9, 0x52, 0x60, 0x85, +0x2d, 0x41, 0xd0, 0x43, 0x01, 0x1e, 0x1c, 0xd5, 0x7d, 0xfc, 0xf3, 0x96, 0x0d, 0xc7, 0xcb, +0x2a, 0x29, 0x9a, 0x93, 0xdd, 0x88, 0x2d, 0x37, 0x5d, 0xaa, 0xfb, 0x49, 0x68, 0xa0, 0x9c, +0x50, 0x86, 0x7f, 0x68, 0x56, 0x57, 0xf9, 0x79, 0x18, 0x39, 0xd4, 0xe0, 0x01, 0x84, 0x33, +0x61, 0xca, 0xa5, 0xd2, 0xd6, 0xe4, 0xc9, 0x8a, 0x4a, 0x23, 0x44, 0x4e, 0xbc, 0xf0, 0xdc, +0x24, 0xa1, 0xa0, 0xc4, 0xe2, 0x07, 0x3c, 0x10, 0xc4, 0xb5, 0x25, 0x4b, 0x65, 0x63, 0xf4, +0x80, 0xe7, 0xcf, 0x61, 0xb1, 0x71, 0x82, 0x21, 0x87, 0x2c, 0xf5, 0x91, 0x00, 0x32, 0x0c, +0xec, 0xa9, 0xb5, 0x9a, 0x74, 0x85, 0xe3, 0x36, 0x8f, 0x76, 0x4f, 0x9c, 0x6d, 0xce, 0xbc, +0xad, 0x0a, 0x4b, 0xed, 0x76, 0x04, 0xcb, 0xc3, 0xb9, 0x33, 0x9e, 0x01, 0x93, 0x96, 0x69, +0x7d, 0xc5, 0xa2, 0x45, 0x79, 0x9b, 0x04, 0x5c, 0x84, 0x09, 0xed, 0x88, 0x43, 0xc7, 0xab, +0x93, 0x14, 0x26, 0xa1, 0x40, 0xb5, 0xce, 0x4e, 0xbf, 0x2a, 0x42, 0x85, 0x3e, 0x2c, 0x3b, +0x54, 0xe8, 0x12, 0x1f, 0x0e, 0x97, 0x59, 0xb2, 0x27, 0x89, 0xfa, 0xf2, 0xdf, 0x8e, 0x68, +0x59, 0xdc, 0x06, 0xbc, 0xb6, 0x85, 0x0d, 0x06, 0x22, 0xec, 0xb1, 0xcb, 0xe5, 0x04, 0xe6, +0x3d, 0xb3, 0xb0, 0x41, 0x73, 0x08, 0x3f, 0x3c, 0x58, 0x86, 0x63, 0xeb, 0x50, 0xee, 0x1d, +0x2c, 0x37, 0x74, 0xa9, 0xd3, 0x18, 0xa3, 0x47, 0x6e, 0x93, 0x54, 0xad, 0x0a, 0x5d, 0xb8, +0x2a, 0x55, 0x5d, 0x78, 0xf6, 0xee, 0xbe, 0x8e, 0x3c, 0x76, 0x69, 0xb9, 0x40, 0xc2, 0x34, +0xec, 0x2a, 0xb9, 0xed, 0x7e, 0x20, 0xe4, 0x8d, 0x00, 0x38, 0xc7, 0xe6, 0x8f, 0x44, 0xa8, +0x86, 0xce, 0xeb, 0x2a, 0xe9, 0x90, 0xf1, 0x4c, 0xdf, 0x32, 0xfb, 0x73, 0x1b, 0x6d, 0x92, +0x1e, 0x95, 0xfe, 0xb4, 0xdb, 0x65, 0xdf, 0x4d, 0x23, 0x54, 0x89, 0x48, 0xbf, 0x4a, 0x2e, +0x70, 0xd6, 0xd7, 0x62, 0xb4, 0x33, 0x29, 0xb1, 0x3a, 0x33, 0x4c, 0x23, 0x6d, 0xa6, 0x76, +0xa5, 0x21, 0x63, 0x48, 0xe6, 0x90, 0x5d, 0xed, 0x90, 0x95, 0x0b, 0x7a, 0x84, 0xbe, 0xb8, +0x0d, 0x5e, 0x63, 0x0c, 0x62, 0x26, 0x4c, 0x14, 0x5a, 0xb3, 0xac, 0x23, 0xa4, 0x74, 0xa7, +0x6f, 0x33, 0x30, 0x05, 0x60, 0x01, 0x42, 0xa0, 0x28, 0xb7, 0xee, 0x19, 0x38, 0xf1, 0x64, +0x80, 0x82, 0x43, 0xe1, 0x41, 0x27, 0x1f, 0x1f, 0x90, 0x54, 0x7a, 0xd5, 0x23, 0x2e, 0xd1, +0x3d, 0xcb, 0x28, 0xba, 0x58, 0x7f, 0xdc, 0x7c, 0x91, 0x24, 0xe9, 0x28, 0x51, 0x83, 0x6e, +0xc5, 0x56, 0x21, 0x42, 0xed, 0xa0, 0x56, 0x22, 0xa1, 0x40, 0x80, 0x6b, 0xa8, 0xf7, 0x94, +0xca, 0x13, 0x6b, 0x0c, 0x39, 0xd9, 0xfd, 0xe9, 0xf3, 0x6f, 0xa6, 0x9e, 0xfc, 0x70, 0x8a, +0xb3, 0xbc, 0x59, 0x3c, 0x1e, 0x1d, 0x6c, 0xf9, 0x7c, 0xaf, 0xf9, 0x88, 0x71, 0x95, 0xeb, +0x57, 0x00, 0xbd, 0x9f, 0x8c, 0x4f, 0xe1, 0x24, 0x83, 0xc5, 0x22, 0xea, 0xfd, 0xd3, 0x0c, +0xe2, 0x17, 0x18, 0x7c, 0x6a, 0x4c, 0xde, 0x77, 0xb4, 0x53, 0x9b, 0x4c, 0x81, 0xcd, 0x23, +0x60, 0xaa, 0x0e, 0x25, 0x73, 0x9c, 0x02, 0x79, 0x32, 0x30, 0xdf, 0x74, 0xdf, 0x75, 0x19, +0xf4, 0xa5, 0x14, 0x5c, 0xf7, 0x7a, 0xa8, 0xa5, 0x91, 0x84, 0x7c, 0x60, 0x03, 0x06, 0x3b, +0xcd, 0x50, 0xb6, 0x27, 0x9c, 0xfe, 0xb1, 0xdd, 0xcc, 0xd3, 0xb0, 0x59, 0x24, 0xb2, 0xca, +0xe2, 0x1c, 0x81, 0x22, 0x9d, 0x07, 0x8f, 0x8e, 0xb9, 0xbe, 0x4e, 0xfa, 0xfc, 0x39, 0x65, +0xba, 0xbf, 0x9d, 0x12, 0x37, 0x5e, 0x97, 0x7e, 0xf3, 0x89, 0xf5, 0x5d, 0xf5, 0xe3, 0x09, +0x8c, 0x62, 0xb5, 0x20, 0x9d, 0x0c, 0x53, 0x8a, 0x68, 0x1b, 0xd2, 0x8f, 0x75, 0x17, 0x5d, +0xd4, 0xe5, 0xda, 0x75, 0x62, 0x19, 0x14, 0x6a, 0x26, 0x2d, 0xeb, 0xf8, 0xaf, 0x37, 0xf0, +0x6c, 0xa4, 0x55, 0xb1, 0xbc, 0xe2, 0x33, 0xc0, 0x9a, 0xca, 0xb0, 0x11, 0x49, 0x4f, 0x68, +0x9b, 0x3b, 0x6b, 0x3c, 0xcc, 0x13, 0xf6, 0xc7, 0x85, 0x61, 0x68, 0x42, 0xae, 0xbb, 0xdd, +0xcd, 0x45, 0x16, 0x29, 0x1d, 0xea, 0xdb, 0xc8, 0x03, 0x94, 0x3c, 0xee, 0x4f, 0x82, 0x11, +0xc3, 0xec, 0x28, 0xbd, 0x97, 0x05, 0x99, 0xde, 0xd7, 0xbb, 0x5e, 0x22, 0x1f, 0xd4, 0xeb, +0x64, 0xd9, 0x92, 0xd9, 0x85, 0xb7, 0x6a, 0x05, 0x6a, 0xe4, 0x24, 0x41, 0xf1, 0xcd, 0xf0, +0xd8, 0x3f, 0xf8, 0x9e, 0x0e, 0xcd, 0x0b, 0x7a, 0x70, 0x6b, 0x5a, 0x75, 0x0a, 0x6a, 0x33, +0x88, 0xec, 0x17, 0x75, 0x08, 0x70, 0x10, 0x2f, 0x24, 0xcf, 0xc4, 0xe9, 0x42, 0x00, 0x61, +0x94, 0xca, 0x1f, 0x3a, 0x76, 0x06, 0xfa, 0xd2, 0x48, 0x81, 0xf0, 0x77, 0x60, 0x03, 0x45, +0xd9, 0x61, 0xf4, 0xa4, 0x6f, 0x3d, 0xd9, 0x30, 0xc3, 0x04, 0x6b, 0x54, 0x2a, 0xb7, 0xec, +0x3b, 0xf4, 0x4b, 0xf5, 0x68, 0x52, 0x26, 0xce, 0xff, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xa5, +0xa9, 0xb1, 0xe0, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0xf9, 0x51, 0x20, 0xa3, 0xa5, 0xa9, 0xb1, +0xc1, 0x00, 0x82, 0x86, 0x8e, 0x7f, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xc4, 0xeb, 0x54, 0x0b, +0x75, 0x68, 0x52, 0x07, 0x8c, 0x9a, 0x97, 0x8d, 0x79, 0x70, 0x62, 0x46, 0xef, 0x5c, 0x1b, +0x95, 0x89, 0x71, 0x41, 0xe1, 0x21, 0xa1, 0xa1, 0xa1, 0xc0, 0x02, 0x67, 0x4c, 0x1a, 0xb6, +0xcf, 0xfd, 0x78, 0x53, 0x24, 0xab, 0xb5, 0xc9, 0xf1, 0x60, 0x23, 0xa5, 0xc8, 0x12, 0x87, +0x6d, 0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x6d, 0x58, 0x32, 0xc7, 0x0c, 0x9a, 0x97, 0xac, +0xda, 0x36, 0xee, 0x5e, 0x3e, 0xdf, 0x1d, 0xb8, 0xf2, 0x66, 0x2f, 0xbd, 0xf8, 0x72, 0x47, +0xed, 0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x8c, 0x7b, 0x55, 0x09, 0x90, 0xa2, 0xc6, 0xef, +0x3d, 0xf8, 0x53, 0x24, 0xab, 0xd4, 0x2a, 0xb7, 0xec, 0x5a, 0x36, 0xee, 0x5e, 0x3e, 0xdf, +0x3c, 0xfa, 0x76, 0x4f, 0xfd, 0x59, 0x30, 0xe2, 0x46, 0xef, 0x3d, 0xf8, 0x53, 0x05, 0x69, +0x31, 0xc1, 0x00, 0x82, 0x86, 0x8e, 0x7f, 0x5d, 0x19, 0xb0, 0xe2, 0x27, 0xcc, 0xfb, 0x74, +0x4b, 0x14, 0x8b, 0x94, 0x8b, 0x75, 0x68, 0x33, 0xc5, 0x08, 0x92, 0x87, 0x8c, 0x9a, 0xb6, +0xcf, 0x1c, 0xba, 0xd7, 0x0d, 0x98, 0xb2, 0xe6, 0x2f, 0xdc, 0x1b, 0x95, 0x89, 0x71, 0x60, +0x23, 0xc4, 0x0a, 0x96, 0x8f, 0x9c, 0xba, 0xf6, 0x6e, 0x3f, 0xfc, 0x5b, 0x15, 0xa8, 0xd2, +0x26, 0xaf, 0xbd, 0xf8, 0x72, 0x66, 0x2f, 0xdc, 0x1b, 0xb4, 0xcb, 0x14, 0x8b, 0x94, 0xaa, +0xb7, 0xcd, 0xf9, 0x51, 0x01, 0x80, 0x82, 0x86, 0x6f, 0x3d, 0xd9, 0x30, 0xe2, 0x27, 0xcc, +0xfb, 0x74, 0x4b, 0x14, 0xaa, 0xb7, 0xcd, 0xf9, 0x70, 0x43, 0x04, 0x6b, 0x35, 0xc9, 0xf1, +0x60, 0x23, 0xa5, 0xc8, 0xf3, 0x45, 0x08, 0x92, 0x87, 0x6d, 0x58, 0x32, 0xe6, 0x2f, 0xbd, +0xf8, 0x72, 0x66, 0x4e, 0x1e, 0xbe, 0xfe, 0x7e, 0x7e, 0x7e, 0x5f, 0x1d, 0x99, 0x91, 0xa0, +0xa3, 0xc4, 0x0a, 0x77, 0x4d, 0x18, 0x93, 0xa4, 0xab, 0xd4, 0x0b, 0x75, 0x49, 0x10, 0xa2, +0xc6, 0xef, 0x3d, 0xf8, 0x53, 0x24, 0xab, 0xb5, 0xe8, 0x33, 0xe4, 0x4a, 0x16, 0xae, 0xde, +0x1f, 0xbc, 0xdb, 0x15, 0xa8, 0xb3, 0xc5, 0x08, 0x73, 0x45, 0xe9, 0x31, 0xc1, 0xe1, 0x21, +0xa1, 0xa1, 0xa1, 0xc0, 0x02, 0x86, 0x6f, 0x5c, 0x3a, 0xd7, 0x0d, 0x98, 0x93, 0xa4, 0xca, +0x16, 0xae, 0xde, 0x1f, 0x9d, 0x99, 0xb0, 0xe2, 0x46, 0xef, 0x3d, 0xf8, 0x72, 0x47, 0x0c, +0x9a, 0xb6, 0xcf, 0xfd, 0x59, 0x11, 0xa0, 0xa3, 0xa5, 0xc8, 0xf3, 0x45, 0x08, 0x92, 0x87, +0x6d, 0x39, 0xf0, 0x43, 0x04, 0x8a, 0x96, 0xae, 0xde, 0x3e, 0xdf, 0x1d, 0x99, 0x91, 0xa0, +0xc2, 0x06, 0x6f, 0x3d, 0xf8, 0x72, 0x47, 0x0c, 0x9a, 0x97, 0x8d, 0x98, 0x93, 0x85, 0x88, +0x73, 0x45, 0xe9, 0x31, 0xe0, 0x23, 0xa5, 0xa9, 0xd0, 0x03, 0x84, 0x8a, 0x96, 0xae, 0xde, +0x1f, 0xbc, 0xdb, 0x15, 0xa8, 0xd2, 0x26, 0xce, 0xff, 0x5d, 0x19, 0x91, 0x81, 0x80, 0x82, +0x67, 0x2d, 0xd8, 0x13, 0xa4, 0xab, 0xd4, 0x0b, 0x94, 0xaa, 0xb7, 0xcd, 0xf9, 0x51, 0x20, +0xa3, 0xa5, 0xc8, 0xf3, 0x45, 0xe9, 0x50, 0x22, 0xc6, 0xef, 0x5c, 0x3a, 0xd7, 0x0d, 0x98, +0x93, 0x85, 0x88, 0x73, 0x64, 0x4a, 0xf7, 0x4d, 0xf9, 0x51, 0x20, 0xa3, 0xc4, 0x0a, 0x96, +0xae, 0xde, 0x3e, 0xfe, 0x7e, 0x7e, 0x7e, 0x5f, 0x3c, 0xfa, 0x76, 0x4f, 0xfd, 0x78, 0x72, +0x66, 0x2f, 0xbd, 0xd9, 0x30, 0xc3, 0xe5, 0x48, 0x12, 0x87, 0x8c, 0x7b, 0x55, 0x28, 0xd2, +0x07, 0x8c, 0x9a, 0x97, 0xac, 0xda, 0x17, 0x8d, 0x79, 0x51, 0x20, 0xa3, 0xc4, 0xeb, 0x54, +0x0b, 0x94, 0x8b, 0x94, 0xaa, 0xd6, 0x2e, 0xbf, 0xfc, 0x5b, 0x15, 0xa8, 0xd2, 0x26, 0xaf, +0xdc, 0x1b, 0xb4, 0xea, 0x37, 0xec, 0x3b, 0xf4, 0x6a, 0x37, 0xcd, 0x18, 0x93, 0x85, 0x69, +0x31, 0xc1, 0xe1, 0x40, 0xe3, 0x25, 0xc8, 0x12, 0x87, 0x8c, 0x9a, 0xb6, 0xcf, 0xfd, 0x59, +0x11, 0xa0, 0xc2, 0x06, 0x8e, 0x7f, 0x5d, 0x38, 0xf2, 0x47, 0x0c, 0x7b, 0x74, 0x6a, 0x37, +0xec, 0x5a, 0x36, 0xee, 0x3f, 0xfc, 0x7a, 0x76, 0x4f, 0x1c, 0x9b, 0x95, 0x89, 0x71, 0x41, +0x00, 0x63, 0x44, 0xeb, 0x54, 0x2a, 0xd6, 0x0f, 0x9c, 0xba, 0xd7, 0x0d, 0x98, 0x93, 0x85, +0x69, 0x31, 0xc1, 0x00, 0x82, 0x86, 0x8e, 0x9e, 0xbe, 0xdf, 0x3c, 0xfa, 0x57, 0x2c, 0xda, +0x36, 0xee, 0x3f, 0xfc, 0x5b, 0x15, 0x89, 0x71, 0x41, 0x00, 0x82, 0x86, 0x8e, 0x7f, 0x5d, +0x38, 0xf2, 0x47, 0xed, 0x58, 0x13, 0xa4, 0xca, 0xf7, 0x4d, 0xf9, 0x51, 0x01, 0x80, 0x63, +0x44, 0xeb, 0x54, 0x2a, 0xd6, 0x2e, 0xbf, 0xdd, 0x19, 0x91, 0xa0, 0xa3, 0xa5, 0xa9, 0xb1, +0xe0, 0x42, 0x06, 0x8e, 0x7f, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xc4, 0x0a, 0x96, 0x8f, 0x7d, +0x78, 0x72, 0x47, 0x0c, 0x7b, 0x74, 0x6a, 0x56, 0x2e, 0xde, 0x1f, 0xbc, 0xfa, 0x57, 0x0d, +0x79, 0x51, 0x01, 0x61, 0x21, 0xa1, 0xc0, 0xe3, 0x25, 0xa9, 0xb1, 0xc1, 0xe1, 0x40, 0x02, +0x67, 0x4c, 0x1a, 0x97, 0x8d, 0x98, 0x93, 0xa4, 0xab, 0xd4, 0x2a, 0xd6, 0x0f, 0x9c, 0x9b, +0xb4, 0xcb, 0x14, 0xaa, 0xb7, 0xcd, 0xf9, 0x51, 0x20, 0xa3, 0xc4, 0xeb, 0x35, 0xc9, 0xf1, +0x60, 0x42, 0x06, 0x8e, 0x7f, 0x7c, 0x7a, 0x76, 0x6e, 0x3f, 0xfc, 0x7a, 0x76, 0x6e, 0x5e, +0x3e, 0xfe, 0x7e, 0x5f, 0x3c, 0xdb, 0x15, 0x89, 0x71, 0x41, 0xe1, 0x21, 0xc0, 0xe3, 0x44, +0xeb, 0x54, 0x2a, 0xb7, 0xcd, 0xf9, 0x70, 0x62, 0x27, 0xad, 0xd8, 0x32, 0xc7, 0x0c, 0x7b, +0x74, 0x4b, 0x14, 0xaa, 0xb7, 0xec, 0x3b, 0xd5, 0x28, 0xd2, 0x07, 0x6d, 0x39, 0xd1, 0x20, +0xc2, 0xe7, 0x4c, 0x1a, 0x97, 0x8d, 0x98, 0xb2, 0xc7, 0x0c, 0x59, 0x28, 0xf3, 0x9b }; diff --git a/app/drivers/sensor/pixart/pmw3610/CMakeLists.txt b/app/drivers/sensor/pixart/pmw3610/CMakeLists.txt new file mode 100644 index 00000000000..6d9c8a6e549 --- /dev/null +++ b/app/drivers/sensor/pixart/pmw3610/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +zephyr_library() + +zephyr_library_sources(pmw3610.c) diff --git a/app/drivers/sensor/pixart/pmw3610/Kconfig b/app/drivers/sensor/pixart/pmw3610/Kconfig new file mode 100644 index 00000000000..7b3d4b74641 --- /dev/null +++ b/app/drivers/sensor/pixart/pmw3610/Kconfig @@ -0,0 +1,103 @@ +# Sensor data simulator +# +# Copyright (c) 2019 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +menuconfig PMW3610 + bool "PMW3610 mouse optical sensor" + select SPI + help + Enable PMW3610 mouse optical sensor. + +if PMW3610 + +config PMW3610_SMART_ALGORITHM + bool "Enable an algorithm of PMW3610 to enhance surface coverage" + default y + help + Enable the integration of the smart algorithm as the datasheet implementation. + The algorithm is used to extend the tracking acrocss a wider range of surfaces + such as graniles and tiles. + +config PMW3610_CPI + int "PMW3610's default CPI" + default 3200 + range 200 3200 + help + Default CPI value, with 200 step + +config PMW3610_CPI_DIVIDOR + int "PMW3610's default CPI dividor" + default 4 + range 1 100 + help + Default CPI dividor value. + +config PMW3610_REST1_SAMPLE_TIME_MS + int "PMW3610's sample time in REST1 stage" + default 100 + range 10 2550 + help + Default REST1 mode sample period in millisecond + +config PMW3610_REST2_SAMPLE_TIME_MS + int "PMW3610's sample time in REST2 stage" + default 200 + range 10 2550 + help + Default REST2 mode sample period in millisecond. + +config PMW3610_REST3_SAMPLE_TIME_MS + int "PMW3610's sample time in REST3 stage" + default 300 + range 10 2550 + help + Default REST2 mode sample period in millisecond. + +config PMW3610_RUN_DOWNSHIFT_TIME_MS + int "PMW3610's default RUN mode downshift time" + default 500 + range 13 3264 + help + Default RUN mode downshift down time in milliseconds. + Time after which sensor goes from RUN to REST1 mode. + +config PMW3610_REST1_DOWNSHIFT_TIME_MS + int "PMW3610's default REST1 mode downshift time" + default 3000 + help + Default REST1 mode downshift down time in milliseconds. + Time after which sensor goes from REST1 to REST2 mode. + +config PMW3610_REST2_DOWNSHIFT_TIME_MS + int "PMW3610's default REST2 mode downshift time" + default 30000 + help + Default REST2 mode downshift down time in milliseconds. + Time after which sensor goes from REST2 to REST3 mode. + +choice + prompt "Select PMW3610 sensor orientation" + default PMW3610_ORIENTATION_0 + +config PMW3610_ORIENTATION_0 + bool "PMW3610 not rotated" + +config PMW3610_ORIENTATION_90 + bool "PMW3610 rotated 90 deg clockwise" + +config PMW3610_ORIENTATION_180 + bool "PMW3610 rotated 180 deg clockwise" + +config PMW3610_ORIENTATION_270 + bool "PMW3610 rotated 270 deg clockwise" + +endchoice + +module = PMW3610 +module-str = PMW3610 +source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config" + +endif #PMW3610 diff --git a/app/drivers/sensor/pixart/pmw3610/pmw3610.c b/app/drivers/sensor/pixart/pmw3610/pmw3610.c new file mode 100644 index 00000000000..5f127a34ee1 --- /dev/null +++ b/app/drivers/sensor/pixart/pmw3610/pmw3610.c @@ -0,0 +1,1044 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT pixart_pmw3610 + +// 12-bit two's complement value to int16_t +// adapted from https://stackoverflow.com/questions/70802306/convert-a-12-bit-signed-number-in-c +#define TOINT16(val, bits) (((struct {int16_t value: bits;}){val}).value) + +#include +#include +#include "pmw3610.h" + +#include +LOG_MODULE_REGISTER(pmw3610, CONFIG_PMW3610_LOG_LEVEL); + +/* Timings (in us) used in SPI communication. Since MCU should not do other tasks during wait, k_busy_wait is used instead of k_sleep */ +// - sub-us time is rounded to us, due to the limitation of k_busy_wait, see : https://github.com/zephyrproject-rtos/zephyr/issues/6498 +#define T_NCS_SCLK 1 /* 120 ns (rounded to 1us) */ +#define T_SCLK_NCS_WR 10 /* 10 us */ +#define T_SRAD 4 /* 4 us */ +#define T_SRAD_MOTBR 4 /* same as T_SRAD */ +#define T_SRX 1 /* 250 ns (rounded to 1 us) */ +#define T_SWX 30 /* SWW: 30 us, SWR: 20 us */ +#define T_BEXIT 1 /* 250 ns (rounded to 1us)*/ + +/* Sensor registers (addresses) */ +#define PMW3610_REG_PRODUCT_ID 0x00 +#define PMW3610_REG_REVISION_ID 0x01 +#define PMW3610_REG_MOTION 0x02 +#define PMW3610_REG_DELTA_X_L 0x03 +#define PMW3610_REG_DELTA_Y_L 0x04 +#define PMW3610_REG_DELTA_XY_H 0x05 +#define PMW3610_REG_SQUAL 0x06 +#define PMW3610_REG_SHUTTER_HIGHER 0x07 +#define PMW3610_REG_SHUTTER_LOWER 0x08 +#define PMW3610_REG_PIX_MAX 0x09 +#define PMW3610_REG_PIX_AVG 0x0A +#define PMW3610_REG_PIX_MIN 0x0B + +#define PMW3610_REG_CRC0 0x0C +#define PMW3610_REG_CRC1 0x0D +#define PMW3610_REG_CRC2 0x0E +#define PMW3610_REG_CRC3 0x0F +#define PMW3610_REG_SELF_TEST 0x10 + +#define PMW3610_REG_PERFORMANCE 0x11 +#define PMW3610_REG_MOTION_BURST 0x12 + +#define PMW3610_REG_RUN_DOWNSHIFT 0x1B +#define PMW3610_REG_REST1_PERIOD 0x1C +#define PMW3610_REG_REST1_DOWNSHIFT 0x1D +#define PMW3610_REG_REST2_PERIOD 0x1E +#define PMW3610_REG_REST2_DOWNSHIFT 0x1F +#define PMW3610_REG_REST3_PERIOD 0x20 +#define PMW3610_REG_OBSERVATION 0x2D + +#define PMW3610_REG_PIXEL_GRAB 0x35 +#define PMW3610_REG_FRAME_GRAB 0x36 + +#define PMW3610_REG_POWER_UP_RESET 0x3A +#define PMW3610_REG_SHUTDOWN 0x3B + +#define PMW3610_REG_SPI_CLK_ON_REQ 0x41 +#define PMW3610_REG_RES_STEP 0x85 + +#define PMW3610_REG_NOT_REV_ID 0x3E +#define PMW3610_REG_NOT_PROD_ID 0x3F + +#define PMW3610_REG_PRBS_TEST_CTL 0x47 +#define PMW3610_REG_SPI_PAGE0 0x7F +#define PMW3610_REG_VCSEL_CTL 0x9E +#define PMW3610_REG_LSR_CONTROL 0x9F +#define PMW3610_REG_SPI_PAGE1 0xFF + +/* Sensor identification values */ +#define PMW3610_PRODUCT_ID 0x3E + +/* Power-up register commands */ +#define PMW3610_POWERUP_CMD_RESET 0x5A +#define PMW3610_POWERUP_CMD_WAKEUP 0x96 + +/* spi clock enable/disable commands */ +#define PMW3610_SPI_CLOCK_CMD_ENABLE 0xBA +#define PMW3610_SPI_CLOCK_CMD_DISABLE 0xB5 + +/* Max register count readable in a single motion burst */ +#define PMW3610_MAX_BURST_SIZE 10 + +/* Register count used for reading a single motion burst */ +#define PMW3610_BURST_SIZE 7 + +/* Position in the motion registers */ +#define PMW3610_X_L_POS 1 +#define PMW3610_Y_L_POS 2 +#define PMW3610_XY_H_POS 3 +#define PMW3610_SHUTTER_H_POS 5 +#define PMW3610_SHUTTER_L_POS 6 + +/* cpi/resolution range */ +#define PMW3610_MAX_CPI 3200 +#define PMW3610_MIN_CPI 200 + +/* write command bit position */ +#define SPI_WRITE_BIT BIT(7) + +/* Helper macros used to convert sensor values. */ +#define PMW3610_SVALUE_TO_CPI(svalue) ((uint32_t)(svalue).val1) +#define PMW3610_SVALUE_TO_TIME(svalue) ((uint32_t)(svalue).val1) + +//////// Sensor initialization steps definition ////////// +// init is done in non-blocking manner (i.e., async), a // +// delayable work is defined for this purpose // +enum pmw3610_init_step { + ASYNC_INIT_STEP_POWER_UP, // reset cs line and assert power-up reset + ASYNC_INIT_STEP_CLEAR_OB1, // clear observation1 register for self-test check + ASYNC_INIT_STEP_CHECK_OB1, // check the value of observation1 register after self-test check + ASYNC_INIT_STEP_CONFIGURE, // set other registes like cpi and donwshift time (run, rest1, rest2) and clear motion registers + + ASYNC_INIT_STEP_COUNT // end flag +}; + +/* Timings (in ms) needed in between steps to allow each step finishes succussfully. */ +// - Since MCU is not involved in the sensor init process, i is allowed to do other tasks. +// Thus, k_sleep or delayed schedule can be used. +static const int32_t async_init_delay[ASYNC_INIT_STEP_COUNT] = { + [ASYNC_INIT_STEP_POWER_UP] = 10, // test shows > 5ms needed + [ASYNC_INIT_STEP_CLEAR_OB1] = 200, // 150 us required, test shows too short, + // also power-up reset is added in this step, thus using 50 ms + [ASYNC_INIT_STEP_CHECK_OB1] = 50, // 10 ms required in spec, + // test shows too short, + // especially when integrated with display, + // > 50ms is needed + [ASYNC_INIT_STEP_CONFIGURE] = 0, +}; + +static int pmw3610_async_init_power_up(const struct device *dev); +static int pmw3610_async_init_clear_ob1(const struct device *dev); +static int pmw3610_async_init_check_ob1(const struct device *dev); +static int pmw3610_async_init_configure(const struct device *dev); + +static int (* const async_init_fn[ASYNC_INIT_STEP_COUNT])(const struct device *dev) = { + [ASYNC_INIT_STEP_POWER_UP] = pmw3610_async_init_power_up, + [ASYNC_INIT_STEP_CLEAR_OB1] = pmw3610_async_init_clear_ob1, + [ASYNC_INIT_STEP_CHECK_OB1] = pmw3610_async_init_check_ob1, + [ASYNC_INIT_STEP_CONFIGURE] = pmw3610_async_init_configure, +}; + +//////// Function definitions ////////// + +// checked and keep +static int spi_cs_ctrl(const struct device *dev, bool enable) +{ + const struct pixart_config *config = dev->config; + int err; + + if (!enable) { + k_busy_wait(T_NCS_SCLK); + } + + err = gpio_pin_set_dt(&config->cs_gpio, (int)enable); + if (err) { + LOG_ERR("SPI CS ctrl failed"); + } + + if (enable) { + k_busy_wait(T_NCS_SCLK); + } + + return err; +} + + +// checked and keep +static int reg_read(const struct device *dev, uint8_t reg, uint8_t *buf) +{ + int err; + /* struct pixart_data *data = dev->data; */ + const struct pixart_config *config = dev->config; + + __ASSERT_NO_MSG((reg & SPI_WRITE_BIT) == 0); + + err = spi_cs_ctrl(dev, true); + if (err) { + return err; + } + + /* Write register address. */ + const struct spi_buf tx_buf = { + .buf = ®, + .len = 1 + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1 + }; + + err = spi_write_dt(&config->bus, &tx); + if (err) { + LOG_ERR("Reg read failed on SPI write"); + return err; + } + + k_busy_wait(T_SRAD); + + /* Read register value. */ + struct spi_buf rx_buf = { + .buf = buf, + .len = 1, + }; + const struct spi_buf_set rx = { + .buffers = &rx_buf, + .count = 1, + }; + + err = spi_read_dt(&config->bus, &rx); + if (err) { + LOG_ERR("Reg read failed on SPI read"); + return err; + } + + err = spi_cs_ctrl(dev, false); + if (err) { + return err; + } + + k_busy_wait(T_SRX); + + return 0; +} + +// primitive write without enable/disable spi clock on the sensor +static int _reg_write(const struct device *dev, uint8_t reg, uint8_t val) +{ + int err; + /* struct pixart_data *data = dev->data; */ + const struct pixart_config *config = dev->config; + + __ASSERT_NO_MSG((reg & SPI_WRITE_BIT) == 0); + + err = spi_cs_ctrl(dev, true); + if (err) { + return err; + } + + uint8_t buf[] = { + SPI_WRITE_BIT | reg, + val + }; + const struct spi_buf tx_buf = { + .buf = buf, + .len = ARRAY_SIZE(buf) + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1 + }; + + err = spi_write_dt(&config->bus, &tx); + if (err) { + LOG_ERR("Reg write failed on SPI write"); + return err; + } + + k_busy_wait(T_SCLK_NCS_WR); + + err = spi_cs_ctrl(dev, false); + if (err) { + return err; + } + + k_busy_wait(T_SWX); + + return 0; +} + +static int reg_write(const struct device *dev, uint8_t reg, uint8_t val) { + int err; + + // enable spi clock + err = _reg_write(dev, PMW3610_REG_SPI_CLK_ON_REQ, PMW3610_SPI_CLOCK_CMD_ENABLE); + if (unlikely(err != 0)) { + return err; + } + + // write the target register + err = _reg_write(dev, reg, val); + if (unlikely(err != 0)) { + return err; + } + + // disable spi clock to save power + err = _reg_write(dev, PMW3610_REG_SPI_CLK_ON_REQ, PMW3610_SPI_CLOCK_CMD_DISABLE); + if (unlikely(err != 0)) { + return err; + } + + return 0; +} + +static int motion_burst_read(const struct device *dev, uint8_t *buf, + size_t burst_size) +{ + int err; + /* struct pixart_data *data = dev->data; */ + const struct pixart_config *config = dev->config; + + __ASSERT_NO_MSG(burst_size <= PMW3610_MAX_BURST_SIZE); + + err = spi_cs_ctrl(dev, true); + if (err) { + return err; + } + + /* Send motion burst address */ + uint8_t reg_buf[] = { + PMW3610_REG_MOTION_BURST + }; + const struct spi_buf tx_buf = { + .buf = reg_buf, + .len = ARRAY_SIZE(reg_buf) + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1 + }; + + err = spi_write_dt(&config->bus, &tx); + if (err) { + LOG_ERR("Motion burst failed on SPI write"); + return err; + } + + k_busy_wait(T_SRAD_MOTBR); + + const struct spi_buf rx_buf = { + .buf = buf, + .len = burst_size, + }; + const struct spi_buf_set rx = { + .buffers = &rx_buf, + .count = 1 + }; + + err = spi_read_dt(&config->bus, &rx); + if (err) { + LOG_ERR("Motion burst failed on SPI read"); + return err; + } + + err = spi_cs_ctrl(dev, false); + if (err) { + return err; + } + + /* Terminate burst */ + k_busy_wait(T_BEXIT); + + return 0; +} + +/** Writing an array of registers in sequence, used in power-up register initialization and running mode switching */ +static int burst_write(const struct device *dev, const uint8_t *addr, const uint8_t *buf, size_t size) +{ + int err; + + // enable spi clock + err = _reg_write(dev, PMW3610_REG_SPI_CLK_ON_REQ, PMW3610_SPI_CLOCK_CMD_ENABLE); + if (unlikely(err != 0)) { + return err; + } + + /* Write data */ + for (size_t i = 0; i < size; i++) { + err = _reg_write(dev, addr[i], buf[i]); + + if (err) { + LOG_ERR("Burst write failed on SPI write (data)"); + return err; + } + } + + // disable spi clock to save power + err = _reg_write(dev, PMW3610_REG_SPI_CLK_ON_REQ, PMW3610_SPI_CLOCK_CMD_DISABLE); + if (unlikely(err != 0)) { + return err; + } + + return 0; +} + +static int check_product_id(const struct device *dev) +{ + uint8_t product_id=0x01; + int err = reg_read(dev, PMW3610_REG_PRODUCT_ID, &product_id); + if (err) { + LOG_ERR("Cannot obtain product id"); + return err; + } + + if (product_id != PMW3610_PRODUCT_ID) { + LOG_ERR("Incorrect product id 0x%x (expecting 0x%x)!", product_id, PMW3610_PRODUCT_ID); + return -EIO; + } + + return 0; +} + +static int set_cpi(const struct device *dev, uint32_t cpi) +{ + /* Set resolution with CPI step of 200 cpi + * 0x1: 200 cpi (minimum cpi) + * 0x2: 400 cpi + * 0x3: 600 cpi + * : + */ + + if ((cpi > PMW3610_MAX_CPI) || (cpi < PMW3610_MIN_CPI)) { + LOG_ERR("CPI value %u out of range", cpi); + return -EINVAL; + } + + // Convert CPI to register value + uint8_t value = (cpi / 200); + LOG_INF("Setting CPI to %u (reg value 0x%x)", cpi, value); + + /* set the cpi */ + uint8_t addr[] = {0x7F, PMW3610_REG_RES_STEP, 0x7F}; + uint8_t data[] = {0xFF, value, 0x00}; + int err = burst_write(dev, addr, data, 3); + if (err) { + LOG_ERR("Failed to set CPI"); + return err; + } + + return 0; +} + +/* Set sampling rate in each mode (in ms) */ +static int set_sample_time(const struct device *dev, uint8_t reg_addr, uint32_t sample_time) +{ + uint32_t maxtime = 2550; + uint32_t mintime = 10; + if ((sample_time > maxtime) || (sample_time < mintime)) { + LOG_WRN("Sample time %u out of range [%u, %u]", sample_time, mintime, maxtime); + return -EINVAL; + } + + uint8_t value = sample_time / mintime; + LOG_INF("Set sample time to %u ms (reg value: 0x%x)", sample_time, value); + + /* The sample time is (reg_value * mintime ) ms. 0x00 is rounded to 0x1 */ + int err = reg_write(dev, reg_addr, value); + if (err) { + LOG_ERR("Failed to change sample time"); + } + + return err; +} + +/* Set downshift time in ms. */ +// NOTE: The unit of run-mode downshift is related to pos mode rate, which is hard coded to be 4 ms +// The pos-mode rate is configured in pmw3610_async_init_configure +static int set_downshift_time(const struct device *dev, uint8_t reg_addr, uint32_t time) +{ + uint32_t maxtime; + uint32_t mintime; + + switch (reg_addr) { + case PMW3610_REG_RUN_DOWNSHIFT: + /* + * Run downshift time = PMW3610_REG_RUN_DOWNSHIFT + * * 8 * pos-rate (fixed to 4ms) + */ + maxtime = 32*255; + mintime = 32; // hard-coded in pmw3610_async_init_configure + break; + + case PMW3610_REG_REST1_DOWNSHIFT: + /* + * Rest1 downshift time = PMW3610_REG_RUN_DOWNSHIFT + * * 16 * Rest1_sample_period (default 40 ms) + */ + maxtime = 255 * 16 * CONFIG_PMW3610_REST1_SAMPLE_TIME_MS; + mintime = 16 * CONFIG_PMW3610_REST1_SAMPLE_TIME_MS; + break; + + case PMW3610_REG_REST2_DOWNSHIFT: + /* + * Rest2 downshift time = PMW3610_REG_REST2_DOWNSHIFT + * * 128 * Rest2 rate (default 100 ms) + */ + maxtime = 255 * 128 * CONFIG_PMW3610_REST2_SAMPLE_TIME_MS; + mintime = 128 * CONFIG_PMW3610_REST2_SAMPLE_TIME_MS; + break; + + default: + LOG_ERR("Not supported"); + return -ENOTSUP; + } + + if ((time > maxtime) || (time < mintime)) { + LOG_WRN("Downshift time %u out of range", time); + return -EINVAL; + } + + __ASSERT_NO_MSG((mintime > 0) && (maxtime/mintime <= UINT8_MAX)); + + /* Convert time to register value */ + uint8_t value = time / mintime; + + LOG_INF("Set downshift time to %u ms (reg value 0x%x)", time, value); + + int err = reg_write(dev, reg_addr, value); + if (err) { + LOG_ERR("Failed to change downshift time"); + } + + return err; +} + +static int pmw3610_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + struct pixart_data *data = dev->data; + int err; + + if (unlikely(chan != SENSOR_CHAN_ALL)) { + return -ENOTSUP; + } + + if (unlikely(!data->ready)) { + LOG_DBG("Device is not initialized yet"); + return -EBUSY; + } + + switch ((uint32_t)attr) { + case PMW3610_ATTR_CPI: + err = set_cpi(dev, PMW3610_SVALUE_TO_CPI(*val)); + break; + + case PMW3610_ATTR_RUN_DOWNSHIFT_TIME: + err = set_downshift_time(dev, + PMW3610_REG_RUN_DOWNSHIFT, + PMW3610_SVALUE_TO_TIME(*val)); + break; + + case PMW3610_ATTR_REST1_DOWNSHIFT_TIME: + err = set_downshift_time(dev, + PMW3610_REG_REST1_DOWNSHIFT, + PMW3610_SVALUE_TO_TIME(*val)); + break; + + case PMW3610_ATTR_REST2_DOWNSHIFT_TIME: + err = set_downshift_time(dev, + PMW3610_REG_REST2_DOWNSHIFT, + PMW3610_SVALUE_TO_TIME(*val)); + break; + + case PMW3610_ATTR_REST1_SAMPLE_TIME: + err = set_sample_time(dev, + PMW3610_REG_REST1_PERIOD, + PMW3610_SVALUE_TO_TIME(*val)); + break; + + case PMW3610_ATTR_REST2_SAMPLE_TIME: + err = set_sample_time(dev, + PMW3610_REG_REST2_PERIOD, + PMW3610_SVALUE_TO_TIME(*val)); + break; + + case PMW3610_ATTR_REST3_SAMPLE_TIME: + err = set_sample_time(dev, + PMW3610_REG_REST3_PERIOD, + PMW3610_SVALUE_TO_TIME(*val)); + break; + + default: + LOG_ERR("Unknown attribute"); + return -ENOTSUP; + } + + return err; +} + +static int pmw3610_async_init_power_up(const struct device *dev) +{ + LOG_INF("async_init_power_up"); + + /* Reset spi port */ + spi_cs_ctrl(dev, false); + spi_cs_ctrl(dev, true); + + /* not required in datashet, but added any way to have a clear state */ + return reg_write(dev, PMW3610_REG_POWER_UP_RESET, PMW3610_POWERUP_CMD_RESET); +} + +static int pmw3610_async_init_clear_ob1(const struct device *dev) +{ + LOG_INF("async_init_clear_ob1"); + + return reg_write(dev, PMW3610_REG_OBSERVATION, 0x00); +} + +static int pmw3610_async_init_check_ob1(const struct device *dev) +{ + LOG_INF("async_init_check_ob1"); + + uint8_t value; + int err = reg_read(dev, PMW3610_REG_OBSERVATION, &value); + if(err) { + LOG_ERR("Can't do self-test"); + return err; + } + + if( (value & 0x0F) != 0x0F ) { + LOG_ERR("Failed self-test (0x%x)", value); + return -EINVAL; + } + + /* err = check_product_id(dev); */ + /* if (err) { */ + /* LOG_ERR("Failed checking product id"); */ + /* return err; */ + /* } */ + + return 0; +} + +static int pmw3610_async_init_configure(const struct device *dev) +{ + LOG_INF("async_init_configure"); + + int err=0; + + // clear motion registers first (required in datasheet) + for (uint8_t reg = 0x02; (reg <= 0x05) && !err; reg++) { + uint8_t buf[1]; + err = reg_read(dev, reg, buf); + } + + // cpi + if (!err) { + err = set_cpi(dev, CONFIG_PMW3610_CPI); + } + + // set performace register: run mode, vel_rate, poshi_rate, poslo_rate + if (!err) { + // use the recommended value in datasheet: normal, 4ms, 4ms, 4ms + err = reg_write(dev, PMW3610_REG_PERFORMANCE, 0x0D); + } + + // sample period, which affects scaling of rest1 downshift time + if (!err) { + err = set_sample_time(dev, + PMW3610_REG_REST1_PERIOD, + CONFIG_PMW3610_REST1_SAMPLE_TIME_MS); + } + + if (!err) { + err = set_sample_time(dev, + PMW3610_REG_REST2_PERIOD, + CONFIG_PMW3610_REST2_SAMPLE_TIME_MS); + } + if (!err) { + err = set_sample_time(dev, + PMW3610_REG_REST3_PERIOD, + CONFIG_PMW3610_REST3_SAMPLE_TIME_MS); + } + + // downshift time for each rest mode + if (!err) { + err = set_downshift_time(dev, + PMW3610_REG_RUN_DOWNSHIFT, + CONFIG_PMW3610_RUN_DOWNSHIFT_TIME_MS); + } + + if (!err) { + err = set_downshift_time(dev, + PMW3610_REG_REST1_DOWNSHIFT, + CONFIG_PMW3610_REST1_DOWNSHIFT_TIME_MS); + } + + if (!err) { + err = set_downshift_time(dev, + PMW3610_REG_REST2_DOWNSHIFT, + CONFIG_PMW3610_REST2_DOWNSHIFT_TIME_MS); + } + + if (err) { + LOG_ERR("Config the sensor failed"); + return err; + } + + return 0; +} + +// checked and keep +static void pmw3610_async_init(struct k_work *work) +{ + struct pixart_data *data = CONTAINER_OF(work, struct pixart_data, + init_work); + const struct device *dev = data->dev; + + LOG_INF("PMW3610 async init step %d", data->async_init_step); + + data->err = async_init_fn[data->async_init_step](dev); + if (data->err) { + LOG_ERR("PMW3610 initialization failed"); + } else { + data->async_init_step++; + + if (data->async_init_step == ASYNC_INIT_STEP_COUNT) { + data->ready = true; // sensor is ready to work + LOG_INF("PMW3610 initialized"); + } else { + k_work_schedule(&data->init_work, + K_MSEC(async_init_delay[data->async_init_step])); + } + } +} + + +static void irq_handler(const struct device *gpiob, struct gpio_callback *cb, + uint32_t pins) +{ + int err; + struct pixart_data *data = CONTAINER_OF(cb, struct pixart_data, + irq_gpio_cb); + const struct device *dev = data->dev; + const struct pixart_config *config = dev->config; + + // disable the interrupt line first + err = gpio_pin_interrupt_configure_dt(&config->irq_gpio, + GPIO_INT_DISABLE); + if (unlikely(err)) { + LOG_ERR("Cannot disable IRQ"); + k_panic(); + } + + // submit the real handler work + k_work_submit(&data->trigger_handler_work); +} + +static void trigger_handler(struct k_work *work) +{ + LOG_DBG("trigger_handler"); + + sensor_trigger_handler_t handler; + int err = 0; + struct pixart_data *data = CONTAINER_OF(work, struct pixart_data, + trigger_handler_work); + const struct device *dev = data->dev; + const struct pixart_config *config = dev->config; + + // 1. the first lock period is used to procoss the trigger + // if data_ready_handler is non-NULL, otherwise do nothing + k_spinlock_key_t key = k_spin_lock(&data->lock); + + handler = data->data_ready_handler; + k_spin_unlock(&data->lock, key); + + if (!handler) { + LOG_DBG("no trigger handler set by application code"); + return; + } + + handler(dev, data->trigger); + + // 2. the second lock period is used to resume the interrupt line + // if data_ready_handler is non-NULL, otherwise keep it inactive + key = k_spin_lock(&data->lock); + if (data->data_ready_handler) { + err = gpio_pin_interrupt_configure_dt(&config->irq_gpio, + GPIO_INT_LEVEL_ACTIVE); + } + k_spin_unlock(&data->lock, key); + + if (unlikely(err)) { + LOG_ERR("Cannot re-enable IRQ"); + k_panic(); + } +} + +static int pmw3610_init_irq(const struct device *dev) +{ + LOG_INF("Configure irq..."); + + int err; + struct pixart_data *data = dev->data; + const struct pixart_config *config = dev->config; + + // check readiness of irq gpio pin + if (!device_is_ready(config->irq_gpio.port)) { + LOG_ERR("IRQ GPIO device not ready"); + return -ENODEV; + } + + // init the irq pin + err = gpio_pin_configure_dt(&config->irq_gpio, GPIO_INPUT); + if (err) { + LOG_ERR("Cannot configure IRQ GPIO"); + return err; + } + + // setup and add the irq callback associated + gpio_init_callback(&data->irq_gpio_cb, irq_handler, + BIT(config->irq_gpio.pin)); + + err = gpio_add_callback(config->irq_gpio.port, &data->irq_gpio_cb); + if (err) { + LOG_ERR("Cannot add IRQ GPIO callback"); + } + + LOG_INF("Configure irq done"); + + return err; +} + +static int pmw3610_init(const struct device *dev) +{ + LOG_INF("Start initializing..."); + + struct pixart_data *data = dev->data; + const struct pixart_config *config = dev->config; + int err; + + // init device pointer + data->dev = dev; + + // init smart algorithm flag; + data->sw_smart_flag = false; + + // init trigger handler work + k_work_init(&data->trigger_handler_work, trigger_handler); + + // check readiness of spi bus + if (!spi_is_ready(&config->bus)) { + LOG_ERR("SPI device not ready"); + return -ENODEV; + } + + // check readiness of cs gpio pin and init it to inactive + if (!device_is_ready(config->cs_gpio.port)) { + LOG_ERR("SPI CS device not ready"); + return -ENODEV; + } + + err = gpio_pin_configure_dt(&config->cs_gpio, GPIO_OUTPUT_INACTIVE); + if (err) { + LOG_ERR("Cannot configure SPI CS GPIO"); + return err; + } + + // init irq routine + err = pmw3610_init_irq(dev); + if (err) { + return err; + } + + // Setup delayable and non-blocking init jobs, including following steps: + // 1. power reset + // 2. upload initial settings + // 3. other configs like cpi, downshift time, sample time etc. + // The sensor is ready to work (i.e., data->ready=true after the above steps are finished) + k_work_init_delayable(&data->init_work, pmw3610_async_init); + + k_work_schedule(&data->init_work, + K_MSEC(async_init_delay[data->async_init_step])); + + return err; +} + +static int pmw3610_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct pixart_data *data = dev->data; + uint8_t buf[PMW3610_BURST_SIZE]; + + if (unlikely(chan != SENSOR_CHAN_ALL)) { + return -ENOTSUP; + } + + if (unlikely(!data->ready)) { + LOG_DBG("Device is not initialized yet"); + return -EBUSY; + } + + int err = motion_burst_read(dev, buf, sizeof(buf)); + + if (!err) { + int16_t x = TOINT16((buf[PMW3610_X_L_POS] + ((buf[PMW3610_XY_H_POS] & 0xF0) << 4)),12) / CONFIG_PMW3610_CPI_DIVIDOR; + int16_t y = TOINT16((buf[PMW3610_Y_L_POS] + ((buf[PMW3610_XY_H_POS] & 0x0F) << 8)),12) / CONFIG_PMW3610_CPI_DIVIDOR; + + if (IS_ENABLED(CONFIG_PMW3610_ORIENTATION_0)) { + data->x = -x; + data->y = y; + } else if (IS_ENABLED(CONFIG_PMW3610_ORIENTATION_90)) { + data->x = y; + data->y = -x; + } else if (IS_ENABLED(CONFIG_PMW3610_ORIENTATION_180)) { + data->x = x; + data->y = -y; + } else if (IS_ENABLED(CONFIG_PMW3610_ORIENTATION_270)) { + data->x = -y; + data->y = x; + } + +#ifdef CONFIG_PMW3610_SMART_ALGORITHM + int16_t shutter = ((int16_t)(buf[PMW3610_SHUTTER_H_POS] & 0x01) << 8) + + buf[PMW3610_SHUTTER_L_POS]; + if ( data->sw_smart_flag && shutter < 45 ) { + reg_write(dev, 0x32, 0x00); + + data->sw_smart_flag = false; + } + + if ( !data->sw_smart_flag && shutter > 45 ) { + reg_write(dev, 0x32, 0x80); + + data->sw_smart_flag = true; + } +#endif + } + + return err; +} + +static int pmw3610_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct pixart_data *data = dev->data; + + if (unlikely(!data->ready)) { + LOG_DBG("Device is not initialized yet"); + return -EBUSY; + } + + switch (chan) { + case SENSOR_CHAN_POS_DX: + val->val1 = data->x; + val->val2 = 0; + break; + + case SENSOR_CHAN_POS_DY: + val->val1 = data->y; + val->val2 = 0; + break; + + default: + return -ENOTSUP; + } + + return 0; +} + +/* Setup the callback for actual trigger handling */ +// handler could be NULL, in which case the effect is disabling the interrupt line +// Thus it has dual function: +// 1. set up a handler callback +// 2. set up a flag (i.e., data_ready_handler) to indicate resuming the interrput line or not +// This feature is useful to pass the resuming of the interrupt to application +static int pmw3610_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + /* LOG_INF("trigger_set"); */ + + struct pixart_data *data = dev->data; + const struct pixart_config *config = dev->config; + int err; + + if (unlikely(trig->type != SENSOR_TRIG_DATA_READY)) { + return -ENOTSUP; + } + + if (unlikely(trig->chan != SENSOR_CHAN_ALL)) { + return -ENOTSUP; + } + + if (unlikely(!data->ready)) { + LOG_DBG("Device is not initialized yet"); + return -EBUSY; + } + + // spin lock is needed, so that the handler is not invoked before its pointer is assigned + // a valid value + k_spinlock_key_t key = k_spin_lock(&data->lock); + + // if non-NULL (a real handler defined), eanble the interrupt line + // otherwise, disable the interrupt line + if (handler) { + err = gpio_pin_interrupt_configure_dt(&config->irq_gpio, + GPIO_INT_LEVEL_ACTIVE); + } else { + err = gpio_pin_interrupt_configure_dt(&config->irq_gpio, + GPIO_INT_DISABLE); + } + + if (!err) { + data->data_ready_handler = handler; + } + + data->trigger = trig; + + k_spin_unlock(&data->lock, key); + + return err; +} + +static const struct sensor_driver_api pmw3610_driver_api = { + .sample_fetch = pmw3610_sample_fetch, + .channel_get = pmw3610_channel_get, + .trigger_set = pmw3610_trigger_set, + .attr_set = pmw3610_attr_set, +}; + +#define PMW3610_DEFINE(n) \ + static struct pixart_data data##n; \ + \ + static const struct pixart_config config##n = { \ + .irq_gpio = GPIO_DT_SPEC_INST_GET(n, irq_gpios), \ + .bus = { \ + .bus = DEVICE_DT_GET(DT_INST_BUS(n)), \ + .config = { \ + .frequency = DT_INST_PROP(n, \ + spi_max_frequency), \ + .operation = SPI_WORD_SET(8) | \ + SPI_TRANSFER_MSB | \ + SPI_MODE_CPOL | SPI_MODE_CPHA, \ + .slave = DT_INST_REG_ADDR(n), \ + }, \ + }, \ + .cs_gpio = SPI_CS_GPIOS_DT_SPEC_GET(DT_DRV_INST(n)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, pmw3610_init, NULL, &data##n, &config##n, \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &pmw3610_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(PMW3610_DEFINE) diff --git a/app/drivers/sensor/pixart/pmw3610/pmw3610.h b/app/drivers/sensor/pixart/pmw3610/pmw3610.h new file mode 100644 index 00000000000..92fd1b11eef --- /dev/null +++ b/app/drivers/sensor/pixart/pmw3610/pmw3610.h @@ -0,0 +1,48 @@ +#ifndef ZEPHYR_INCLUDE_PMW3610_H_ +#define ZEPHYR_INCLUDE_PMW3610_H_ + +#include "../pixart.h" + +/** + * @file pmw3610.h + * + * @brief Header file for the pmw3610 driver. + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + enum pmw3610_attribute { + /** Sensor CPI for both X and Y axes. */ + PMW3610_ATTR_CPI = SENSOR_ATTR_PRIV_START, + + /** Entering time from Run mode to REST1 mode [ms]. */ + PMW3610_ATTR_RUN_DOWNSHIFT_TIME, + + /** Entering time from REST1 mode to REST2 mode [ms]. */ + PMW3610_ATTR_REST1_DOWNSHIFT_TIME, + + /** Entering time from REST2 mode to REST3 mode [ms]. */ + PMW3610_ATTR_REST2_DOWNSHIFT_TIME, + + /** Sampling frequency time during REST1 mode [ms]. */ + PMW3610_ATTR_REST1_SAMPLE_TIME, + + /** Sampling frequency time during REST2 mode [ms]. */ + PMW3610_ATTR_REST2_SAMPLE_TIME, + + /** Sampling frequency time during REST3 mode [ms]. */ + PMW3610_ATTR_REST3_SAMPLE_TIME, + }; + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_PMW3610_H_ */ diff --git a/app/drivers/sensor/pmw33xx/.gitignore b/app/drivers/sensor/pmw33xx/.gitignore new file mode 100644 index 00000000000..ee2a286bb29 --- /dev/null +++ b/app/drivers/sensor/pmw33xx/.gitignore @@ -0,0 +1 @@ +pmw3389_srom.h diff --git a/app/drivers/sensor/pmw33xx/CMakeLists.txt b/app/drivers/sensor/pmw33xx/CMakeLists.txt new file mode 100644 index 00000000000..011b4cac058 --- /dev/null +++ b/app/drivers/sensor/pmw33xx/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +zephyr_include_directories(.) +zephyr_include_directories_ifdef(CONFIG_PMW33XX_3389 CONFIG_PMW33XX_3389_SROM_INCLUDE_DIR) + +zephyr_library() + +zephyr_library_sources(pmw33xx.c) +zephyr_library_sources_ifdef(CONFIG_PMW33XX_TRIGGER pmw33xx_trigger.c) diff --git a/app/drivers/sensor/pmw33xx/Kconfig b/app/drivers/sensor/pmw33xx/Kconfig new file mode 100644 index 00000000000..b6a926f0224 --- /dev/null +++ b/app/drivers/sensor/pmw33xx/Kconfig @@ -0,0 +1,69 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT +config PMW33XX + bool "PMW33XX Mouse Sensor" + depends on SPI + help + Enable mouse sensor + + The PMW33XX is a 16-bit optical mouse sensor + +if PMW33XX +choice + prompt "Sensor" + default PMW33XX_3360 + + config PMW33XX_3360 + bool "Enable PMW3360" + + config PMW33XX_3389 + bool "Enable PMW3389" + help + PMW3389 requires an external srom included in `pmw3389_srom.h` which we cannot currently include in zmk +endchoice + +config PMW33XX_3389_SROM_INCLUDE_DIR + string "PMW3389 SROM Include Dir" + default "." + help + directory where the header with the pmw3389 srom file is located + +choice + prompt "Trigger mode" + default PMW33XX_TRIGGER_NONE + help + Specify the type of triggering to be used by the driver. + +config PMW33XX_TRIGGER_NONE + bool "No trigger" + +config PMW33XX_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + depends on GPIO + select PMW33XX_TRIGGER + +config PMW33XX_TRIGGER_OWN_THREAD + bool "Use own thread" + depends on GPIO + select PMW33XX_TRIGGER + +endchoice + +config PMW33XX_TRIGGER + bool + +config PMW33XX_THREAD_PRIORITY + int "Thread priority" + depends on PMW33XX_TRIGGER_OWN_THREAD + default 10 + help + Priority of thread used by the driver to handle interrupts. + +config PMW33XX_THREAD_STACK_SIZE + int "Thread stack size" + depends on PMW33XX_TRIGGER_OWN_THREAD + default 1024 + help + Stack size of thread used by the driver to handle interrupts. + +endif # PMW33XX diff --git a/app/drivers/sensor/pmw33xx/pmw3360_srom.h b/app/drivers/sensor/pmw33xx/pmw3360_srom.h new file mode 100644 index 00000000000..f0290128386 --- /dev/null +++ b/app/drivers/sensor/pmw33xx/pmw3360_srom.h @@ -0,0 +1,294 @@ +/* +This SROM is provided "AS IS" by PixArt Imaging Inc., WITHOUT WARRANTY +OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL PIXART +IMAGING INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THIS +SROM OR THE USE OR OTHER DEALINGS IN THIS SROM. +*/ + +#ifndef ZEPHYR_DRIVERS_SENSOR_PIXART_PMW33XX_PMW3360_SROM_H_ +#define ZEPHYR_DRIVERS_SENSOR_PIXART_PMW33XX_PMW3360_SROM_H_ + +// firmware vesion id (the second byte in srom hex array) +#define PMW3360_FIRMWARE_ID 0x04 + +#include +static const uint8_t SROM[] = { +0x01, 0x04, 0x8e, 0x96, 0x6e, 0x77, 0x3e, 0xfe, 0x7e, 0x5f, 0x1d, 0xb8, 0xf2, 0x66, 0x4e, +0xff, 0x5d, 0x19, 0xb0, 0xc2, 0x04, 0x69, 0x54, 0x2a, 0xd6, 0x2e, 0xbf, 0xdd, 0x19, 0xb0, +0xc3, 0xe5, 0x29, 0xb1, 0xe0, 0x23, 0xa5, 0xa9, 0xb1, 0xc1, 0x00, 0x82, 0x67, 0x4c, 0x1a, +0x97, 0x8d, 0x79, 0x51, 0x20, 0xc7, 0x06, 0x8e, 0x7c, 0x7c, 0x7a, 0x76, 0x4f, 0xfd, 0x59, +0x30, 0xe2, 0x46, 0x0e, 0x9e, 0xbe, 0xdf, 0x1d, 0x99, 0x91, 0xa0, 0xa5, 0xa1, 0xa9, 0xd0, +0x22, 0xc6, 0xef, 0x5c, 0x1b, 0x95, 0x89, 0x90, 0xa2, 0xa7, 0xcc, 0xfb, 0x55, 0x28, 0xb3, +0xe4, 0x4a, 0xf7, 0x6c, 0x3b, 0xf4, 0x6a, 0x56, 0x2e, 0xde, 0x1f, 0x9d, 0xb8, 0xd3, 0x05, +0x88, 0x92, 0xa6, 0xce, 0x1e, 0xbe, 0xdf, 0x1d, 0x99, 0xb0, 0xe2, 0x46, 0xef, 0x5c, 0x07, +0x11, 0x5d, 0x98, 0x0b, 0x9d, 0x94, 0x97, 0xee, 0x4e, 0x45, 0x33, 0x6b, 0x44, 0xc7, 0x29, +0x56, 0x27, 0x30, 0xc6, 0xa7, 0xd5, 0xf2, 0x56, 0xdf, 0xb4, 0x38, 0x62, 0xcb, 0xa0, 0xb6, +0xe3, 0x0f, 0x84, 0x06, 0x24, 0x05, 0x65, 0x6f, 0x76, 0x89, 0xb5, 0x77, 0x41, 0x27, 0x82, +0x66, 0x65, 0x82, 0xcc, 0xd5, 0xe6, 0x20, 0xd5, 0x27, 0x17, 0xc5, 0xf8, 0x03, 0x23, 0x7c, +0x5f, 0x64, 0xa5, 0x1d, 0xc1, 0xd6, 0x36, 0xcb, 0x4c, 0xd4, 0xdb, 0x66, 0xd7, 0x8b, 0xb1, +0x99, 0x7e, 0x6f, 0x4c, 0x36, 0x40, 0x06, 0xd6, 0xeb, 0xd7, 0xa2, 0xe4, 0xf4, 0x95, 0x51, +0x5a, 0x54, 0x96, 0xd5, 0x53, 0x44, 0xd7, 0x8c, 0xe0, 0xb9, 0x40, 0x68, 0xd2, 0x18, 0xe9, +0xdd, 0x9a, 0x23, 0x92, 0x48, 0xee, 0x7f, 0x43, 0xaf, 0xea, 0x77, 0x38, 0x84, 0x8c, 0x0a, +0x72, 0xaf, 0x69, 0xf8, 0xdd, 0xf1, 0x24, 0x83, 0xa3, 0xf8, 0x4a, 0xbf, 0xf5, 0x94, 0x13, +0xdb, 0xbb, 0xd8, 0xb4, 0xb3, 0xa0, 0xfb, 0x45, 0x50, 0x60, 0x30, 0x59, 0x12, 0x31, 0x71, +0xa2, 0xd3, 0x13, 0xe7, 0xfa, 0xe7, 0xce, 0x0f, 0x63, 0x15, 0x0b, 0x6b, 0x94, 0xbb, 0x37, +0x83, 0x26, 0x05, 0x9d, 0xfb, 0x46, 0x92, 0xfc, 0x0a, 0x15, 0xd1, 0x0d, 0x73, 0x92, 0xd6, +0x8c, 0x1b, 0x8c, 0xb8, 0x55, 0x8a, 0xce, 0xbd, 0xfe, 0x8e, 0xfc, 0xed, 0x09, 0x12, 0x83, +0x91, 0x82, 0x51, 0x31, 0x23, 0xfb, 0xb4, 0x0c, 0x76, 0xad, 0x7c, 0xd9, 0xb4, 0x4b, 0xb2, +0x67, 0x14, 0x09, 0x9c, 0x7f, 0x0c, 0x18, 0xba, 0x3b, 0xd6, 0x8e, 0x14, 0x2a, 0xe4, 0x1b, +0x52, 0x9f, 0x2b, 0x7d, 0xe1, 0xfb, 0x6a, 0x33, 0x02, 0xfa, 0xac, 0x5a, 0xf2, 0x3e, 0x88, +0x7e, 0xae, 0xd1, 0xf3, 0x78, 0xe8, 0x05, 0xd1, 0xe3, 0xdc, 0x21, 0xf6, 0xe1, 0x9a, 0xbd, +0x17, 0x0e, 0xd9, 0x46, 0x9b, 0x88, 0x03, 0xea, 0xf6, 0x66, 0xbe, 0x0e, 0x1b, 0x50, 0x49, +0x96, 0x40, 0x97, 0xf1, 0xf1, 0xe4, 0x80, 0xa6, 0x6e, 0xe8, 0x77, 0x34, 0xbf, 0x29, 0x40, +0x44, 0xc2, 0xff, 0x4e, 0x98, 0xd3, 0x9c, 0xa3, 0x32, 0x2b, 0x76, 0x51, 0x04, 0x09, 0xe7, +0xa9, 0xd1, 0xa6, 0x32, 0xb1, 0x23, 0x53, 0xe2, 0x47, 0xab, 0xd6, 0xf5, 0x69, 0x5c, 0x3e, +0x5f, 0xfa, 0xae, 0x45, 0x20, 0xe5, 0xd2, 0x44, 0xff, 0x39, 0x32, 0x6d, 0xfd, 0x27, 0x57, +0x5c, 0xfd, 0xf0, 0xde, 0xc1, 0xb5, 0x99, 0xe5, 0xf5, 0x1c, 0x77, 0x01, 0x75, 0xc5, 0x6d, +0x58, 0x92, 0xf2, 0xb2, 0x47, 0x00, 0x01, 0x26, 0x96, 0x7a, 0x30, 0xff, 0xb7, 0xf0, 0xef, +0x77, 0xc1, 0x8a, 0x5d, 0xdc, 0xc0, 0xd1, 0x29, 0x30, 0x1e, 0x77, 0x38, 0x7a, 0x94, 0xf1, +0xb8, 0x7a, 0x7e, 0xef, 0xa4, 0xd1, 0xac, 0x31, 0x4a, 0xf2, 0x5d, 0x64, 0x3d, 0xb2, 0xe2, +0xf0, 0x08, 0x99, 0xfc, 0x70, 0xee, 0x24, 0xa7, 0x7e, 0xee, 0x1e, 0x20, 0x69, 0x7d, 0x44, +0xbf, 0x87, 0x42, 0xdf, 0x88, 0x3b, 0x0c, 0xda, 0x42, 0xc9, 0x04, 0xf9, 0x45, 0x50, 0xfc, +0x83, 0x8f, 0x11, 0x6a, 0x72, 0xbc, 0x99, 0x95, 0xf0, 0xac, 0x3d, 0xa7, 0x3b, 0xcd, 0x1c, +0xe2, 0x88, 0x79, 0x37, 0x11, 0x5f, 0x39, 0x89, 0x95, 0x0a, 0x16, 0x84, 0x7a, 0xf6, 0x8a, +0xa4, 0x28, 0xe4, 0xed, 0x83, 0x80, 0x3b, 0xb1, 0x23, 0xa5, 0x03, 0x10, 0xf4, 0x66, 0xea, +0xbb, 0x0c, 0x0f, 0xc5, 0xec, 0x6c, 0x69, 0xc5, 0xd3, 0x24, 0xab, 0xd4, 0x2a, 0xb7, 0x99, +0x88, 0x76, 0x08, 0xa0, 0xa8, 0x95, 0x7c, 0xd8, 0x38, 0x6d, 0xcd, 0x59, 0x02, 0x51, 0x4b, +0xf1, 0xb5, 0x2b, 0x50, 0xe3, 0xb6, 0xbd, 0xd0, 0x72, 0xcf, 0x9e, 0xfd, 0x6e, 0xbb, 0x44, +0xc8, 0x24, 0x8a, 0x77, 0x18, 0x8a, 0x13, 0x06, 0xef, 0x97, 0x7d, 0xfa, 0x81, 0xf0, 0x31, +0xe6, 0xfa, 0x77, 0xed, 0x31, 0x06, 0x31, 0x5b, 0x54, 0x8a, 0x9f, 0x30, 0x68, 0xdb, 0xe2, +0x40, 0xf8, 0x4e, 0x73, 0xfa, 0xab, 0x74, 0x8b, 0x10, 0x58, 0x13, 0xdc, 0xd2, 0xe6, 0x78, +0xd1, 0x32, 0x2e, 0x8a, 0x9f, 0x2c, 0x58, 0x06, 0x48, 0x27, 0xc5, 0xa9, 0x5e, 0x81, 0x47, +0x89, 0x46, 0x21, 0x91, 0x03, 0x70, 0xa4, 0x3e, 0x88, 0x9c, 0xda, 0x33, 0x0a, 0xce, 0xbc, +0x8b, 0x8e, 0xcf, 0x9f, 0xd3, 0x71, 0x80, 0x43, 0xcf, 0x6b, 0xa9, 0x51, 0x83, 0x76, 0x30, +0x82, 0xc5, 0x6a, 0x85, 0x39, 0x11, 0x50, 0x1a, 0x82, 0xdc, 0x1e, 0x1c, 0xd5, 0x7d, 0xa9, +0x71, 0x99, 0x33, 0x47, 0x19, 0x97, 0xb3, 0x5a, 0xb1, 0xdf, 0xed, 0xa4, 0xf2, 0xe6, 0x26, +0x84, 0xa2, 0x28, 0x9a, 0x9e, 0xdf, 0xa6, 0x6a, 0xf4, 0xd6, 0xfc, 0x2e, 0x5b, 0x9d, 0x1a, +0x2a, 0x27, 0x68, 0xfb, 0xc1, 0x83, 0x21, 0x4b, 0x90, 0xe0, 0x36, 0xdd, 0x5b, 0x31, 0x42, +0x55, 0xa0, 0x13, 0xf7, 0xd0, 0x89, 0x53, 0x71, 0x99, 0x57, 0x09, 0x29, 0xc5, 0xf3, 0x21, +0xf8, 0x37, 0x2f, 0x40, 0xf3, 0xd4, 0xaf, 0x16, 0x08, 0x36, 0x02, 0xfc, 0x77, 0xc5, 0x8b, +0x04, 0x90, 0x56, 0xb9, 0xc9, 0x67, 0x9a, 0x99, 0xe8, 0x00, 0xd3, 0x86, 0xff, 0x97, 0x2d, +0x08, 0xe9, 0xb7, 0xb3, 0x91, 0xbc, 0xdf, 0x45, 0xc6, 0xed, 0x0f, 0x8c, 0x4c, 0x1e, 0xe6, +0x5b, 0x6e, 0x38, 0x30, 0xe4, 0xaa, 0xe3, 0x95, 0xde, 0xb9, 0xe4, 0x9a, 0xf5, 0xb2, 0x55, +0x9a, 0x87, 0x9b, 0xf6, 0x6a, 0xb2, 0xf2, 0x77, 0x9a, 0x31, 0xf4, 0x7a, 0x31, 0xd1, 0x1d, +0x04, 0xc0, 0x7c, 0x32, 0xa2, 0x9e, 0x9a, 0xf5, 0x62, 0xf8, 0x27, 0x8d, 0xbf, 0x51, 0xff, +0xd3, 0xdf, 0x64, 0x37, 0x3f, 0x2a, 0x6f, 0x76, 0x3a, 0x7d, 0x77, 0x06, 0x9e, 0x77, 0x7f, +0x5e, 0xeb, 0x32, 0x51, 0xf9, 0x16, 0x66, 0x9a, 0x09, 0xf3, 0xb0, 0x08, 0xa4, 0x70, 0x96, +0x46, 0x30, 0xff, 0xda, 0x4f, 0xe9, 0x1b, 0xed, 0x8d, 0xf8, 0x74, 0x1f, 0x31, 0x92, 0xb3, +0x73, 0x17, 0x36, 0xdb, 0x91, 0x30, 0xd6, 0x88, 0x55, 0x6b, 0x34, 0x77, 0x87, 0x7a, 0xe7, +0xee, 0x06, 0xc6, 0x1c, 0x8c, 0x19, 0x0c, 0x48, 0x46, 0x23, 0x5e, 0x9c, 0x07, 0x5c, 0xbf, +0xb4, 0x7e, 0xd6, 0x4f, 0x74, 0x9c, 0xe2, 0xc5, 0x50, 0x8b, 0xc5, 0x8b, 0x15, 0x90, 0x60, +0x62, 0x57, 0x29, 0xd0, 0x13, 0x43, 0xa1, 0x80, 0x88, 0x91, 0x00, 0x44, 0xc7, 0x4d, 0x19, +0x86, 0xcc, 0x2f, 0x2a, 0x75, 0x5a, 0xfc, 0xeb, 0x97, 0x2a, 0x70, 0xe3, 0x78, 0xd8, 0x91, +0xb0, 0x4f, 0x99, 0x07, 0xa3, 0x95, 0xea, 0x24, 0x21, 0xd5, 0xde, 0x51, 0x20, 0x93, 0x27, +0x0a, 0x30, 0x73, 0xa8, 0xff, 0x8a, 0x97, 0xe9, 0xa7, 0x6a, 0x8e, 0x0d, 0xe8, 0xf0, 0xdf, +0xec, 0xea, 0xb4, 0x6c, 0x1d, 0x39, 0x2a, 0x62, 0x2d, 0x3d, 0x5a, 0x8b, 0x65, 0xf8, 0x90, +0x05, 0x2e, 0x7e, 0x91, 0x2c, 0x78, 0xef, 0x8e, 0x7a, 0xc1, 0x2f, 0xac, 0x78, 0xee, 0xaf, +0x28, 0x45, 0x06, 0x4c, 0x26, 0xaf, 0x3b, 0xa2, 0xdb, 0xa3, 0x93, 0x06, 0xb5, 0x3c, 0xa5, +0xd8, 0xee, 0x8f, 0xaf, 0x25, 0xcc, 0x3f, 0x85, 0x68, 0x48, 0xa9, 0x62, 0xcc, 0x97, 0x8f, +0x7f, 0x2a, 0xea, 0xe0, 0x15, 0x0a, 0xad, 0x62, 0x07, 0xbd, 0x45, 0xf8, 0x41, 0xd8, 0x36, +0xcb, 0x4c, 0xdb, 0x6e, 0xe6, 0x3a, 0xe7, 0xda, 0x15, 0xe9, 0x29, 0x1e, 0x12, 0x10, 0xa0, +0x14, 0x2c, 0x0e, 0x3d, 0xf4, 0xbf, 0x39, 0x41, 0x92, 0x75, 0x0b, 0x25, 0x7b, 0xa3, 0xce, +0x39, 0x9c, 0x15, 0x64, 0xc8, 0xfa, 0x3d, 0xef, 0x73, 0x27, 0xfe, 0x26, 0x2e, 0xce, 0xda, +0x6e, 0xfd, 0x71, 0x8e, 0xdd, 0xfe, 0x76, 0xee, 0xdc, 0x12, 0x5c, 0x02, 0xc5, 0x3a, 0x4e, +0x4e, 0x4f, 0xbf, 0xca, 0x40, 0x15, 0xc7, 0x6e, 0x8d, 0x41, 0xf1, 0x10, 0xe0, 0x4f, 0x7e, +0x97, 0x7f, 0x1c, 0xae, 0x47, 0x8e, 0x6b, 0xb1, 0x25, 0x31, 0xb0, 0x73, 0xc7, 0x1b, 0x97, +0x79, 0xf9, 0x80, 0xd3, 0x66, 0x22, 0x30, 0x07, 0x74, 0x1e, 0xe4, 0xd0, 0x80, 0x21, 0xd6, +0xee, 0x6b, 0x6c, 0x4f, 0xbf, 0xf5, 0xb7, 0xd9, 0x09, 0x87, 0x2f, 0xa9, 0x14, 0xbe, 0x27, +0xd9, 0x72, 0x50, 0x01, 0xd4, 0x13, 0x73, 0xa6, 0xa7, 0x51, 0x02, 0x75, 0x25, 0xe1, 0xb3, +0x45, 0x34, 0x7d, 0xa8, 0x8e, 0xeb, 0xf3, 0x16, 0x49, 0xcb, 0x4f, 0x8c, 0xa1, 0xb9, 0x36, +0x85, 0x39, 0x75, 0x5d, 0x08, 0x00, 0xae, 0xeb, 0xf6, 0xea, 0xd7, 0x13, 0x3a, 0x21, 0x5a, +0x5f, 0x30, 0x84, 0x52, 0x26, 0x95, 0xc9, 0x14, 0xf2, 0x57, 0x55, 0x6b, 0xb1, 0x10, 0xc2, +0xe1, 0xbd, 0x3b, 0x51, 0xc0, 0xb7, 0x55, 0x4c, 0x71, 0x12, 0x26, 0xc7, 0x0d, 0xf9, 0x51, +0xa4, 0x38, 0x02, 0x05, 0x7f, 0xb8, 0xf1, 0x72, 0x4b, 0xbf, 0x71, 0x89, 0x14, 0xf3, 0x77, +0x38, 0xd9, 0x71, 0x24, 0xf3, 0x00, 0x11, 0xa1, 0xd8, 0xd4, 0x69, 0x27, 0x08, 0x37, 0x35, +0xc9, 0x11, 0x9d, 0x90, 0x1c, 0x0e, 0xe7, 0x1c, 0xff, 0x2d, 0x1e, 0xe8, 0x92, 0xe1, 0x18, +0x10, 0x95, 0x7c, 0xe0, 0x80, 0xf4, 0x96, 0x43, 0x21, 0xf9, 0x75, 0x21, 0x64, 0x38, 0xdd, +0x9f, 0x1e, 0x95, 0x16, 0xda, 0x56, 0x1d, 0x4f, 0x9a, 0x53, 0xb2, 0xe2, 0xe4, 0x18, 0xcb, +0x6b, 0x1a, 0x65, 0xeb, 0x56, 0xc6, 0x3b, 0xe5, 0xfe, 0xd8, 0x26, 0x3f, 0x3a, 0x84, 0x59, +0x72, 0x66, 0xa2, 0xf3, 0x75, 0xff, 0xfb, 0x60, 0xb3, 0x22, 0xad, 0x3f, 0x2d, 0x6b, 0xf9, +0xeb, 0xea, 0x05, 0x7c, 0xd8, 0x8f, 0x6d, 0x2c, 0x98, 0x9e, 0x2b, 0x93, 0xf1, 0x5e, 0x46, +0xf0, 0x87, 0x49, 0x29, 0x73, 0x68, 0xd7, 0x7f, 0xf9, 0xf0, 0xe5, 0x7d, 0xdb, 0x1d, 0x75, +0x19, 0xf3, 0xc4, 0x58, 0x9b, 0x17, 0x88, 0xa8, 0x92, 0xe0, 0xbe, 0xbd, 0x8b, 0x1d, 0x8d, +0x9f, 0x56, 0x76, 0xad, 0xaf, 0x29, 0xe2, 0xd9, 0xd5, 0x52, 0xf6, 0xb5, 0x56, 0x35, 0x57, +0x3a, 0xc8, 0xe1, 0x56, 0x43, 0x19, 0x94, 0xd3, 0x04, 0x9b, 0x6d, 0x35, 0xd8, 0x0b, 0x5f, +0x4d, 0x19, 0x8e, 0xec, 0xfa, 0x64, 0x91, 0x0a, 0x72, 0x20, 0x2b, 0xbc, 0x1a, 0x4a, 0xfe, +0x8b, 0xfd, 0xbb, 0xed, 0x1b, 0x23, 0xea, 0xad, 0x72, 0x82, 0xa1, 0x29, 0x99, 0x71, 0xbd, +0xf0, 0x95, 0xc1, 0x03, 0xdd, 0x7b, 0xc2, 0xb2, 0x3c, 0x28, 0x54, 0xd3, 0x68, 0xa4, 0x72, +0xc8, 0x66, 0x96, 0xe0, 0xd1, 0xd8, 0x7f, 0xf8, 0xd1, 0x26, 0x2b, 0xf7, 0xad, 0xba, 0x55, +0xca, 0x15, 0xb9, 0x32, 0xc3, 0xe5, 0x88, 0x97, 0x8e, 0x5c, 0xfb, 0x92, 0x25, 0x8b, 0xbf, +0xa2, 0x45, 0x55, 0x7a, 0xa7, 0x6f, 0x8b, 0x57, 0x5b, 0xcf, 0x0e, 0xcb, 0x1d, 0xfb, 0x20, +0x82, 0x77, 0xa8, 0x8c, 0xcc, 0x16, 0xce, 0x1d, 0xfa, 0xde, 0xcc, 0x0b, 0x62, 0xfe, 0xcc, +0xe1, 0xb7, 0xf0, 0xc3, 0x81, 0x64, 0x73, 0x40, 0xa0, 0xc2, 0x4d, 0x89, 0x11, 0x75, 0x33, +0x55, 0x33, 0x8d, 0xe8, 0x4a, 0xfd, 0xea, 0x6e, 0x30, 0x0b, 0xd7, 0x31, 0x2c, 0xde, 0x47, +0xe3, 0xbf, 0xf8, 0x55, 0x42, 0xe2, 0x7f, 0x59, 0xe5, 0x17, 0xef, 0x99, 0x34, 0x69, 0x91, +0xb1, 0x23, 0x8e, 0x20, 0x87, 0x2d, 0xa8, 0xfe, 0xd5, 0x8a, 0xf3, 0x84, 0x3a, 0xf0, 0x37, +0xe4, 0x09, 0x00, 0x54, 0xee, 0x67, 0x49, 0x93, 0xe4, 0x81, 0x70, 0xe3, 0x90, 0x4d, 0xef, +0xfe, 0x41, 0xb7, 0x99, 0x7b, 0xc1, 0x83, 0xba, 0x62, 0x12, 0x6f, 0x7d, 0xde, 0x6b, 0xaf, +0xda, 0x16, 0xf9, 0x55, 0x51, 0xee, 0xa6, 0x0c, 0x2b, 0x02, 0xa3, 0xfd, 0x8d, 0xfb, 0x30, +0x17, 0xe4, 0x6f, 0xdf, 0x36, 0x71, 0xc4, 0xca, 0x87, 0x25, 0x48, 0xb0, 0x47, 0xec, 0xea, +0xb4, 0xbf, 0xa5, 0x4d, 0x9b, 0x9f, 0x02, 0x93, 0xc4, 0xe3, 0xe4, 0xe8, 0x42, 0x2d, 0x68, +0x81, 0x15, 0x0a, 0xeb, 0x84, 0x5b, 0xd6, 0xa8, 0x74, 0xfb, 0x7d, 0x1d, 0xcb, 0x2c, 0xda, +0x46, 0x2a, 0x76, 0x62, 0xce, 0xbc, 0x5c, 0x9e, 0x8b, 0xe7, 0xcf, 0xbe, 0x78, 0xf5, 0x7c, +0xeb, 0xb3, 0x3a, 0x9c, 0xaa, 0x6f, 0xcc, 0x72, 0xd1, 0x59, 0xf2, 0x11, 0x23, 0xd6, 0x3f, +0x48, 0xd1, 0xb7, 0xce, 0xb0, 0xbf, 0xcb, 0xea, 0x80, 0xde, 0x57, 0xd4, 0x5e, 0x97, 0x2f, +0x75, 0xd1, 0x50, 0x8e, 0x80, 0x2c, 0x66, 0x79, 0xbf, 0x72, 0x4b, 0xbd, 0x8a, 0x81, 0x6c, +0xd3, 0xe1, 0x01, 0xdc, 0xd2, 0x15, 0x26, 0xc5, 0x36, 0xda, 0x2c, 0x1a, 0xc0, 0x27, 0x94, +0xed, 0xb7, 0x9b, 0x85, 0x0b, 0x5e, 0x80, 0x97, 0xc5, 0xec, 0x4f, 0xec, 0x88, 0x5d, 0x50, +0x07, 0x35, 0x47, 0xdc, 0x0b, 0x3b, 0x3d, 0xdd, 0x60, 0xaf, 0xa8, 0x5d, 0x81, 0x38, 0x24, +0x25, 0x5d, 0x5c, 0x15, 0xd1, 0xde, 0xb3, 0xab, 0xec, 0x05, 0x69, 0xef, 0x83, 0xed, 0x57, +0x54, 0xb8, 0x64, 0x64, 0x11, 0x16, 0x32, 0x69, 0xda, 0x9f, 0x2d, 0x7f, 0x36, 0xbb, 0x44, +0x5a, 0x34, 0xe8, 0x7f, 0xbf, 0x03, 0xeb, 0x00, 0x7f, 0x59, 0x68, 0x22, 0x79, 0xcf, 0x73, +0x6c, 0x2c, 0x29, 0xa7, 0xa1, 0x5f, 0x38, 0xa1, 0x1d, 0xf0, 0x20, 0x53, 0xe0, 0x1a, 0x63, +0x14, 0x58, 0x71, 0x10, 0xaa, 0x08, 0x0c, 0x3e, 0x16, 0x1a, 0x60, 0x22, 0x82, 0x7f, 0xba, +0xa4, 0x43, 0xa0, 0xd0, 0xac, 0x1b, 0xd5, 0x6b, 0x64, 0xb5, 0x14, 0x93, 0x31, 0x9e, 0x53, +0x50, 0xd0, 0x57, 0x66, 0xee, 0x5a, 0x4f, 0xfb, 0x03, 0x2a, 0x69, 0x58, 0x76, 0xf1, 0x83, +0xf7, 0x4e, 0xba, 0x8c, 0x42, 0x06, 0x60, 0x5d, 0x6d, 0xce, 0x60, 0x88, 0xae, 0xa4, 0xc3, +0xf1, 0x03, 0xa5, 0x4b, 0x98, 0xa1, 0xff, 0x67, 0xe1, 0xac, 0xa2, 0xb8, 0x62, 0xd7, 0x6f, +0xa0, 0x31, 0xb4, 0xd2, 0x77, 0xaf, 0x21, 0x10, 0x06, 0xc6, 0x9a, 0xff, 0x1d, 0x09, 0x17, +0x0e, 0x5f, 0xf1, 0xaa, 0x54, 0x34, 0x4b, 0x45, 0x8a, 0x87, 0x63, 0xa6, 0xdc, 0xf9, 0x24, +0x30, 0x67, 0xc6, 0xb2, 0xd6, 0x61, 0x33, 0x69, 0xee, 0x50, 0x61, 0x57, 0x28, 0xe7, 0x7e, +0xee, 0xec, 0x3a, 0x5a, 0x73, 0x4e, 0xa8, 0x8d, 0xe4, 0x18, 0xea, 0xec, 0x41, 0x64, 0xc8, +0xe2, 0xe8, 0x66, 0xb6, 0x2d, 0xb6, 0xfb, 0x6a, 0x6c, 0x16, 0xb3, 0xdd, 0x46, 0x43, 0xb9, +0x73, 0x00, 0x6a, 0x71, 0xed, 0x4e, 0x9d, 0x25, 0x1a, 0xc3, 0x3c, 0x4a, 0x95, 0x15, 0x99, +0x35, 0x81, 0x14, 0x02, 0xd6, 0x98, 0x9b, 0xec, 0xd8, 0x23, 0x3b, 0x84, 0x29, 0xaf, 0x0c, +0x99, 0x83, 0xa6, 0x9a, 0x34, 0x4f, 0xfa, 0xe8, 0xd0, 0x3c, 0x4b, 0xd0, 0xfb, 0xb6, 0x68, +0xb8, 0x9e, 0x8f, 0xcd, 0xf7, 0x60, 0x2d, 0x7a, 0x22, 0xe5, 0x7d, 0xab, 0x65, 0x1b, 0x95, +0xa7, 0xa8, 0x7f, 0xb6, 0x77, 0x47, 0x7b, 0x5f, 0x8b, 0x12, 0x72, 0xd0, 0xd4, 0x91, 0xef, +0xde, 0x19, 0x50, 0x3c, 0xa7, 0x8b, 0xc4, 0xa9, 0xb3, 0x23, 0xcb, 0x76, 0xe6, 0x81, 0xf0, +0xc1, 0x04, 0x8f, 0xa3, 0xb8, 0x54, 0x5b, 0x97, 0xac, 0x19, 0xff, 0x3f, 0x55, 0x27, 0x2f, +0xe0, 0x1d, 0x42, 0x9b, 0x57, 0xfc, 0x4b, 0x4e, 0x0f, 0xce, 0x98, 0xa9, 0x43, 0x57, 0x03, +0xbd, 0xe7, 0xc8, 0x94, 0xdf, 0x6e, 0x36, 0x73, 0x32, 0xb4, 0xef, 0x2e, 0x85, 0x7a, 0x6e, +0xfc, 0x6c, 0x18, 0x82, 0x75, 0x35, 0x90, 0x07, 0xf3, 0xe4, 0x9f, 0x3e, 0xdc, 0x68, 0xf3, +0xb5, 0xf3, 0x19, 0x80, 0x92, 0x06, 0x99, 0xa2, 0xe8, 0x6f, 0xff, 0x2e, 0x7f, 0xae, 0x42, +0xa4, 0x5f, 0xfb, 0xd4, 0x0e, 0x81, 0x2b, 0xc3, 0x04, 0xff, 0x2b, 0xb3, 0x74, 0x4e, 0x36, +0x5b, 0x9c, 0x15, 0x00, 0xc6, 0x47, 0x2b, 0xe8, 0x8b, 0x3d, 0xf1, 0x9c, 0x03, 0x9a, 0x58, +0x7f, 0x9b, 0x9c, 0xbf, 0x85, 0x49, 0x79, 0x35, 0x2e, 0x56, 0x7b, 0x41, 0x14, 0x39, 0x47, +0x83, 0x26, 0xaa, 0x07, 0x89, 0x98, 0x11, 0x1b, 0x86, 0xe7, 0x73, 0x7a, 0xd8, 0x7d, 0x78, +0x61, 0x53, 0xe9, 0x79, 0xf5, 0x36, 0x8d, 0x44, 0x92, 0x84, 0xf9, 0x13, 0x50, 0x58, 0x3b, +0xa4, 0x6a, 0x36, 0x65, 0x49, 0x8e, 0x3c, 0x0e, 0xf1, 0x6f, 0xd2, 0x84, 0xc4, 0x7e, 0x8e, +0x3f, 0x39, 0xae, 0x7c, 0x84, 0xf1, 0x63, 0x37, 0x8e, 0x3c, 0xcc, 0x3e, 0x44, 0x81, 0x45, +0xf1, 0x4b, 0xb9, 0xed, 0x6b, 0x36, 0x5d, 0xbb, 0x20, 0x60, 0x1a, 0x0f, 0xa3, 0xaa, 0x55, +0x77, 0x3a, 0xa9, 0xae, 0x37, 0x4d, 0xba, 0xb8, 0x86, 0x6b, 0xbc, 0x08, 0x50, 0xf6, 0xcc, +0xa4, 0xbd, 0x1d, 0x40, 0x72, 0xa5, 0x86, 0xfa, 0xe2, 0x10, 0xae, 0x3d, 0x58, 0x4b, 0x97, +0xf3, 0x43, 0x74, 0xa9, 0x9e, 0xeb, 0x21, 0xb7, 0x01, 0xa4, 0x86, 0x93, 0x97, 0xee, 0x2f, +0x4f, 0x3b, 0x86, 0xa1, 0x41, 0x6f, 0x41, 0x26, 0x90, 0x78, 0x5c, 0x7f, 0x30, 0x38, 0x4b, +0x3f, 0xaa, 0xec, 0xed, 0x5c, 0x6f, 0x0e, 0xad, 0x43, 0x87, 0xfd, 0x93, 0x35, 0xe6, 0x01, +0xef, 0x41, 0x26, 0x90, 0x99, 0x9e, 0xfb, 0x19, 0x5b, 0xad, 0xd2, 0x91, 0x8a, 0xe0, 0x46, +0xaf, 0x65, 0xfa, 0x4f, 0x84, 0xc1, 0xa1, 0x2d, 0xcf, 0x45, 0x8b, 0xd3, 0x85, 0x50, 0x55, +0x7c, 0xf9, 0x67, 0x88, 0xd4, 0x4e, 0xe9, 0xd7, 0x6b, 0x61, 0x54, 0xa1, 0xa4, 0xa6, 0xa2, +0xc2, 0xbf, 0x30, 0x9c, 0x40, 0x9f, 0x5f, 0xd7, 0x69, 0x2b, 0x24, 0x82, 0x5e, 0xd9, 0xd6, +0xa7, 0x12, 0x54, 0x1a, 0xf7, 0x55, 0x9f, 0x76, 0x50, 0xa9, 0x95, 0x84, 0xe6, 0x6b, 0x6d, +0xb5, 0x96, 0x54, 0xd6, 0xcd, 0xb3, 0xa1, 0x9b, 0x46, 0xa7, 0x94, 0x4d, 0xc4, 0x94, 0xb4, +0x98, 0xe3, 0xe1, 0xe2, 0x34, 0xd5, 0x33, 0x16, 0x07, 0x54, 0xcd, 0xb7, 0x77, 0x53, 0xdb, +0x4f, 0x4d, 0x46, 0x9d, 0xe9, 0xd4, 0x9c, 0x8a, 0x36, 0xb6, 0xb8, 0x38, 0x26, 0x6c, 0x0e, +0xff, 0x9c, 0x1b, 0x43, 0x8b, 0x80, 0xcc, 0xb9, 0x3d, 0xda, 0xc7, 0xf1, 0x8a, 0xf2, 0x6d, +0xb8, 0xd7, 0x74, 0x2f, 0x7e, 0x1e, 0xb7, 0xd3, 0x4a, 0xb4, 0xac, 0xfc, 0x79, 0x48, 0x6c, +0xbc, 0x96, 0xb6, 0x94, 0x46, 0x57, 0x2d, 0xb0, 0xa3, 0xfc, 0x1e, 0xb9, 0x52, 0x60, 0x85, +0x2d, 0x41, 0xd0, 0x43, 0x01, 0x1e, 0x1c, 0xd5, 0x7d, 0xfc, 0xf3, 0x96, 0x0d, 0xc7, 0xcb, +0x2a, 0x29, 0x9a, 0x93, 0xdd, 0x88, 0x2d, 0x37, 0x5d, 0xaa, 0xfb, 0x49, 0x68, 0xa0, 0x9c, +0x50, 0x86, 0x7f, 0x68, 0x56, 0x57, 0xf9, 0x79, 0x18, 0x39, 0xd4, 0xe0, 0x01, 0x84, 0x33, +0x61, 0xca, 0xa5, 0xd2, 0xd6, 0xe4, 0xc9, 0x8a, 0x4a, 0x23, 0x44, 0x4e, 0xbc, 0xf0, 0xdc, +0x24, 0xa1, 0xa0, 0xc4, 0xe2, 0x07, 0x3c, 0x10, 0xc4, 0xb5, 0x25, 0x4b, 0x65, 0x63, 0xf4, +0x80, 0xe7, 0xcf, 0x61, 0xb1, 0x71, 0x82, 0x21, 0x87, 0x2c, 0xf5, 0x91, 0x00, 0x32, 0x0c, +0xec, 0xa9, 0xb5, 0x9a, 0x74, 0x85, 0xe3, 0x36, 0x8f, 0x76, 0x4f, 0x9c, 0x6d, 0xce, 0xbc, +0xad, 0x0a, 0x4b, 0xed, 0x76, 0x04, 0xcb, 0xc3, 0xb9, 0x33, 0x9e, 0x01, 0x93, 0x96, 0x69, +0x7d, 0xc5, 0xa2, 0x45, 0x79, 0x9b, 0x04, 0x5c, 0x84, 0x09, 0xed, 0x88, 0x43, 0xc7, 0xab, +0x93, 0x14, 0x26, 0xa1, 0x40, 0xb5, 0xce, 0x4e, 0xbf, 0x2a, 0x42, 0x85, 0x3e, 0x2c, 0x3b, +0x54, 0xe8, 0x12, 0x1f, 0x0e, 0x97, 0x59, 0xb2, 0x27, 0x89, 0xfa, 0xf2, 0xdf, 0x8e, 0x68, +0x59, 0xdc, 0x06, 0xbc, 0xb6, 0x85, 0x0d, 0x06, 0x22, 0xec, 0xb1, 0xcb, 0xe5, 0x04, 0xe6, +0x3d, 0xb3, 0xb0, 0x41, 0x73, 0x08, 0x3f, 0x3c, 0x58, 0x86, 0x63, 0xeb, 0x50, 0xee, 0x1d, +0x2c, 0x37, 0x74, 0xa9, 0xd3, 0x18, 0xa3, 0x47, 0x6e, 0x93, 0x54, 0xad, 0x0a, 0x5d, 0xb8, +0x2a, 0x55, 0x5d, 0x78, 0xf6, 0xee, 0xbe, 0x8e, 0x3c, 0x76, 0x69, 0xb9, 0x40, 0xc2, 0x34, +0xec, 0x2a, 0xb9, 0xed, 0x7e, 0x20, 0xe4, 0x8d, 0x00, 0x38, 0xc7, 0xe6, 0x8f, 0x44, 0xa8, +0x86, 0xce, 0xeb, 0x2a, 0xe9, 0x90, 0xf1, 0x4c, 0xdf, 0x32, 0xfb, 0x73, 0x1b, 0x6d, 0x92, +0x1e, 0x95, 0xfe, 0xb4, 0xdb, 0x65, 0xdf, 0x4d, 0x23, 0x54, 0x89, 0x48, 0xbf, 0x4a, 0x2e, +0x70, 0xd6, 0xd7, 0x62, 0xb4, 0x33, 0x29, 0xb1, 0x3a, 0x33, 0x4c, 0x23, 0x6d, 0xa6, 0x76, +0xa5, 0x21, 0x63, 0x48, 0xe6, 0x90, 0x5d, 0xed, 0x90, 0x95, 0x0b, 0x7a, 0x84, 0xbe, 0xb8, +0x0d, 0x5e, 0x63, 0x0c, 0x62, 0x26, 0x4c, 0x14, 0x5a, 0xb3, 0xac, 0x23, 0xa4, 0x74, 0xa7, +0x6f, 0x33, 0x30, 0x05, 0x60, 0x01, 0x42, 0xa0, 0x28, 0xb7, 0xee, 0x19, 0x38, 0xf1, 0x64, +0x80, 0x82, 0x43, 0xe1, 0x41, 0x27, 0x1f, 0x1f, 0x90, 0x54, 0x7a, 0xd5, 0x23, 0x2e, 0xd1, +0x3d, 0xcb, 0x28, 0xba, 0x58, 0x7f, 0xdc, 0x7c, 0x91, 0x24, 0xe9, 0x28, 0x51, 0x83, 0x6e, +0xc5, 0x56, 0x21, 0x42, 0xed, 0xa0, 0x56, 0x22, 0xa1, 0x40, 0x80, 0x6b, 0xa8, 0xf7, 0x94, +0xca, 0x13, 0x6b, 0x0c, 0x39, 0xd9, 0xfd, 0xe9, 0xf3, 0x6f, 0xa6, 0x9e, 0xfc, 0x70, 0x8a, +0xb3, 0xbc, 0x59, 0x3c, 0x1e, 0x1d, 0x6c, 0xf9, 0x7c, 0xaf, 0xf9, 0x88, 0x71, 0x95, 0xeb, +0x57, 0x00, 0xbd, 0x9f, 0x8c, 0x4f, 0xe1, 0x24, 0x83, 0xc5, 0x22, 0xea, 0xfd, 0xd3, 0x0c, +0xe2, 0x17, 0x18, 0x7c, 0x6a, 0x4c, 0xde, 0x77, 0xb4, 0x53, 0x9b, 0x4c, 0x81, 0xcd, 0x23, +0x60, 0xaa, 0x0e, 0x25, 0x73, 0x9c, 0x02, 0x79, 0x32, 0x30, 0xdf, 0x74, 0xdf, 0x75, 0x19, +0xf4, 0xa5, 0x14, 0x5c, 0xf7, 0x7a, 0xa8, 0xa5, 0x91, 0x84, 0x7c, 0x60, 0x03, 0x06, 0x3b, +0xcd, 0x50, 0xb6, 0x27, 0x9c, 0xfe, 0xb1, 0xdd, 0xcc, 0xd3, 0xb0, 0x59, 0x24, 0xb2, 0xca, +0xe2, 0x1c, 0x81, 0x22, 0x9d, 0x07, 0x8f, 0x8e, 0xb9, 0xbe, 0x4e, 0xfa, 0xfc, 0x39, 0x65, +0xba, 0xbf, 0x9d, 0x12, 0x37, 0x5e, 0x97, 0x7e, 0xf3, 0x89, 0xf5, 0x5d, 0xf5, 0xe3, 0x09, +0x8c, 0x62, 0xb5, 0x20, 0x9d, 0x0c, 0x53, 0x8a, 0x68, 0x1b, 0xd2, 0x8f, 0x75, 0x17, 0x5d, +0xd4, 0xe5, 0xda, 0x75, 0x62, 0x19, 0x14, 0x6a, 0x26, 0x2d, 0xeb, 0xf8, 0xaf, 0x37, 0xf0, +0x6c, 0xa4, 0x55, 0xb1, 0xbc, 0xe2, 0x33, 0xc0, 0x9a, 0xca, 0xb0, 0x11, 0x49, 0x4f, 0x68, +0x9b, 0x3b, 0x6b, 0x3c, 0xcc, 0x13, 0xf6, 0xc7, 0x85, 0x61, 0x68, 0x42, 0xae, 0xbb, 0xdd, +0xcd, 0x45, 0x16, 0x29, 0x1d, 0xea, 0xdb, 0xc8, 0x03, 0x94, 0x3c, 0xee, 0x4f, 0x82, 0x11, +0xc3, 0xec, 0x28, 0xbd, 0x97, 0x05, 0x99, 0xde, 0xd7, 0xbb, 0x5e, 0x22, 0x1f, 0xd4, 0xeb, +0x64, 0xd9, 0x92, 0xd9, 0x85, 0xb7, 0x6a, 0x05, 0x6a, 0xe4, 0x24, 0x41, 0xf1, 0xcd, 0xf0, +0xd8, 0x3f, 0xf8, 0x9e, 0x0e, 0xcd, 0x0b, 0x7a, 0x70, 0x6b, 0x5a, 0x75, 0x0a, 0x6a, 0x33, +0x88, 0xec, 0x17, 0x75, 0x08, 0x70, 0x10, 0x2f, 0x24, 0xcf, 0xc4, 0xe9, 0x42, 0x00, 0x61, +0x94, 0xca, 0x1f, 0x3a, 0x76, 0x06, 0xfa, 0xd2, 0x48, 0x81, 0xf0, 0x77, 0x60, 0x03, 0x45, +0xd9, 0x61, 0xf4, 0xa4, 0x6f, 0x3d, 0xd9, 0x30, 0xc3, 0x04, 0x6b, 0x54, 0x2a, 0xb7, 0xec, +0x3b, 0xf4, 0x4b, 0xf5, 0x68, 0x52, 0x26, 0xce, 0xff, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xa5, +0xa9, 0xb1, 0xe0, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0xf9, 0x51, 0x20, 0xa3, 0xa5, 0xa9, 0xb1, +0xc1, 0x00, 0x82, 0x86, 0x8e, 0x7f, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xc4, 0xeb, 0x54, 0x0b, +0x75, 0x68, 0x52, 0x07, 0x8c, 0x9a, 0x97, 0x8d, 0x79, 0x70, 0x62, 0x46, 0xef, 0x5c, 0x1b, +0x95, 0x89, 0x71, 0x41, 0xe1, 0x21, 0xa1, 0xa1, 0xa1, 0xc0, 0x02, 0x67, 0x4c, 0x1a, 0xb6, +0xcf, 0xfd, 0x78, 0x53, 0x24, 0xab, 0xb5, 0xc9, 0xf1, 0x60, 0x23, 0xa5, 0xc8, 0x12, 0x87, +0x6d, 0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x6d, 0x58, 0x32, 0xc7, 0x0c, 0x9a, 0x97, 0xac, +0xda, 0x36, 0xee, 0x5e, 0x3e, 0xdf, 0x1d, 0xb8, 0xf2, 0x66, 0x2f, 0xbd, 0xf8, 0x72, 0x47, +0xed, 0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x8c, 0x7b, 0x55, 0x09, 0x90, 0xa2, 0xc6, 0xef, +0x3d, 0xf8, 0x53, 0x24, 0xab, 0xd4, 0x2a, 0xb7, 0xec, 0x5a, 0x36, 0xee, 0x5e, 0x3e, 0xdf, +0x3c, 0xfa, 0x76, 0x4f, 0xfd, 0x59, 0x30, 0xe2, 0x46, 0xef, 0x3d, 0xf8, 0x53, 0x05, 0x69, +0x31, 0xc1, 0x00, 0x82, 0x86, 0x8e, 0x7f, 0x5d, 0x19, 0xb0, 0xe2, 0x27, 0xcc, 0xfb, 0x74, +0x4b, 0x14, 0x8b, 0x94, 0x8b, 0x75, 0x68, 0x33, 0xc5, 0x08, 0x92, 0x87, 0x8c, 0x9a, 0xb6, +0xcf, 0x1c, 0xba, 0xd7, 0x0d, 0x98, 0xb2, 0xe6, 0x2f, 0xdc, 0x1b, 0x95, 0x89, 0x71, 0x60, +0x23, 0xc4, 0x0a, 0x96, 0x8f, 0x9c, 0xba, 0xf6, 0x6e, 0x3f, 0xfc, 0x5b, 0x15, 0xa8, 0xd2, +0x26, 0xaf, 0xbd, 0xf8, 0x72, 0x66, 0x2f, 0xdc, 0x1b, 0xb4, 0xcb, 0x14, 0x8b, 0x94, 0xaa, +0xb7, 0xcd, 0xf9, 0x51, 0x01, 0x80, 0x82, 0x86, 0x6f, 0x3d, 0xd9, 0x30, 0xe2, 0x27, 0xcc, +0xfb, 0x74, 0x4b, 0x14, 0xaa, 0xb7, 0xcd, 0xf9, 0x70, 0x43, 0x04, 0x6b, 0x35, 0xc9, 0xf1, +0x60, 0x23, 0xa5, 0xc8, 0xf3, 0x45, 0x08, 0x92, 0x87, 0x6d, 0x58, 0x32, 0xe6, 0x2f, 0xbd, +0xf8, 0x72, 0x66, 0x4e, 0x1e, 0xbe, 0xfe, 0x7e, 0x7e, 0x7e, 0x5f, 0x1d, 0x99, 0x91, 0xa0, +0xa3, 0xc4, 0x0a, 0x77, 0x4d, 0x18, 0x93, 0xa4, 0xab, 0xd4, 0x0b, 0x75, 0x49, 0x10, 0xa2, +0xc6, 0xef, 0x3d, 0xf8, 0x53, 0x24, 0xab, 0xb5, 0xe8, 0x33, 0xe4, 0x4a, 0x16, 0xae, 0xde, +0x1f, 0xbc, 0xdb, 0x15, 0xa8, 0xb3, 0xc5, 0x08, 0x73, 0x45, 0xe9, 0x31, 0xc1, 0xe1, 0x21, +0xa1, 0xa1, 0xa1, 0xc0, 0x02, 0x86, 0x6f, 0x5c, 0x3a, 0xd7, 0x0d, 0x98, 0x93, 0xa4, 0xca, +0x16, 0xae, 0xde, 0x1f, 0x9d, 0x99, 0xb0, 0xe2, 0x46, 0xef, 0x3d, 0xf8, 0x72, 0x47, 0x0c, +0x9a, 0xb6, 0xcf, 0xfd, 0x59, 0x11, 0xa0, 0xa3, 0xa5, 0xc8, 0xf3, 0x45, 0x08, 0x92, 0x87, +0x6d, 0x39, 0xf0, 0x43, 0x04, 0x8a, 0x96, 0xae, 0xde, 0x3e, 0xdf, 0x1d, 0x99, 0x91, 0xa0, +0xc2, 0x06, 0x6f, 0x3d, 0xf8, 0x72, 0x47, 0x0c, 0x9a, 0x97, 0x8d, 0x98, 0x93, 0x85, 0x88, +0x73, 0x45, 0xe9, 0x31, 0xe0, 0x23, 0xa5, 0xa9, 0xd0, 0x03, 0x84, 0x8a, 0x96, 0xae, 0xde, +0x1f, 0xbc, 0xdb, 0x15, 0xa8, 0xd2, 0x26, 0xce, 0xff, 0x5d, 0x19, 0x91, 0x81, 0x80, 0x82, +0x67, 0x2d, 0xd8, 0x13, 0xa4, 0xab, 0xd4, 0x0b, 0x94, 0xaa, 0xb7, 0xcd, 0xf9, 0x51, 0x20, +0xa3, 0xa5, 0xc8, 0xf3, 0x45, 0xe9, 0x50, 0x22, 0xc6, 0xef, 0x5c, 0x3a, 0xd7, 0x0d, 0x98, +0x93, 0x85, 0x88, 0x73, 0x64, 0x4a, 0xf7, 0x4d, 0xf9, 0x51, 0x20, 0xa3, 0xc4, 0x0a, 0x96, +0xae, 0xde, 0x3e, 0xfe, 0x7e, 0x7e, 0x7e, 0x5f, 0x3c, 0xfa, 0x76, 0x4f, 0xfd, 0x78, 0x72, +0x66, 0x2f, 0xbd, 0xd9, 0x30, 0xc3, 0xe5, 0x48, 0x12, 0x87, 0x8c, 0x7b, 0x55, 0x28, 0xd2, +0x07, 0x8c, 0x9a, 0x97, 0xac, 0xda, 0x17, 0x8d, 0x79, 0x51, 0x20, 0xa3, 0xc4, 0xeb, 0x54, +0x0b, 0x94, 0x8b, 0x94, 0xaa, 0xd6, 0x2e, 0xbf, 0xfc, 0x5b, 0x15, 0xa8, 0xd2, 0x26, 0xaf, +0xdc, 0x1b, 0xb4, 0xea, 0x37, 0xec, 0x3b, 0xf4, 0x6a, 0x37, 0xcd, 0x18, 0x93, 0x85, 0x69, +0x31, 0xc1, 0xe1, 0x40, 0xe3, 0x25, 0xc8, 0x12, 0x87, 0x8c, 0x9a, 0xb6, 0xcf, 0xfd, 0x59, +0x11, 0xa0, 0xc2, 0x06, 0x8e, 0x7f, 0x5d, 0x38, 0xf2, 0x47, 0x0c, 0x7b, 0x74, 0x6a, 0x37, +0xec, 0x5a, 0x36, 0xee, 0x3f, 0xfc, 0x7a, 0x76, 0x4f, 0x1c, 0x9b, 0x95, 0x89, 0x71, 0x41, +0x00, 0x63, 0x44, 0xeb, 0x54, 0x2a, 0xd6, 0x0f, 0x9c, 0xba, 0xd7, 0x0d, 0x98, 0x93, 0x85, +0x69, 0x31, 0xc1, 0x00, 0x82, 0x86, 0x8e, 0x9e, 0xbe, 0xdf, 0x3c, 0xfa, 0x57, 0x2c, 0xda, +0x36, 0xee, 0x3f, 0xfc, 0x5b, 0x15, 0x89, 0x71, 0x41, 0x00, 0x82, 0x86, 0x8e, 0x7f, 0x5d, +0x38, 0xf2, 0x47, 0xed, 0x58, 0x13, 0xa4, 0xca, 0xf7, 0x4d, 0xf9, 0x51, 0x01, 0x80, 0x63, +0x44, 0xeb, 0x54, 0x2a, 0xd6, 0x2e, 0xbf, 0xdd, 0x19, 0x91, 0xa0, 0xa3, 0xa5, 0xa9, 0xb1, +0xe0, 0x42, 0x06, 0x8e, 0x7f, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xc4, 0x0a, 0x96, 0x8f, 0x7d, +0x78, 0x72, 0x47, 0x0c, 0x7b, 0x74, 0x6a, 0x56, 0x2e, 0xde, 0x1f, 0xbc, 0xfa, 0x57, 0x0d, +0x79, 0x51, 0x01, 0x61, 0x21, 0xa1, 0xc0, 0xe3, 0x25, 0xa9, 0xb1, 0xc1, 0xe1, 0x40, 0x02, +0x67, 0x4c, 0x1a, 0x97, 0x8d, 0x98, 0x93, 0xa4, 0xab, 0xd4, 0x2a, 0xd6, 0x0f, 0x9c, 0x9b, +0xb4, 0xcb, 0x14, 0xaa, 0xb7, 0xcd, 0xf9, 0x51, 0x20, 0xa3, 0xc4, 0xeb, 0x35, 0xc9, 0xf1, +0x60, 0x42, 0x06, 0x8e, 0x7f, 0x7c, 0x7a, 0x76, 0x6e, 0x3f, 0xfc, 0x7a, 0x76, 0x6e, 0x5e, +0x3e, 0xfe, 0x7e, 0x5f, 0x3c, 0xdb, 0x15, 0x89, 0x71, 0x41, 0xe1, 0x21, 0xc0, 0xe3, 0x44, +0xeb, 0x54, 0x2a, 0xb7, 0xcd, 0xf9, 0x70, 0x62, 0x27, 0xad, 0xd8, 0x32, 0xc7, 0x0c, 0x7b, +0x74, 0x4b, 0x14, 0xaa, 0xb7, 0xec, 0x3b, 0xd5, 0x28, 0xd2, 0x07, 0x6d, 0x39, 0xd1, 0x20, +0xc2, 0xe7, 0x4c, 0x1a, 0x97, 0x8d, 0x98, 0xb2, 0xc7, 0x0c, 0x59, 0x28, 0xf3, 0x9b +}; +#endif diff --git a/app/drivers/sensor/pmw33xx/pmw33xx.c b/app/drivers/sensor/pmw33xx/pmw33xx.c new file mode 100644 index 00000000000..0994c9e2e2a --- /dev/null +++ b/app/drivers/sensor/pmw33xx/pmw33xx.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ +#define DT_DRV_COMPAT pixart_pmw33xx + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_PMW33XX_3389 +#include +#elif CONFIG_PMW33XX_3360 +#include +#endif + +#include "pmw33xx.h" + +LOG_MODULE_REGISTER(PMW33XX, CONFIG_SENSOR_LOG_LEVEL); + +#define PMW33XX_PID COND_CODE_1(CONFIG_PMW33XX_3389, (PMW33XX_3389_PID), (PMW33XX_3360_PID)) +#define PMW33XX_CPI_MAX \ + COND_CODE_1(CONFIG_PMW33XX_3389, (PMW33XX_3389_CPI_MAX), (PMW33XX_3360_CPI_MAX)) +#define PMW33XX_CPI_MIN \ + COND_CODE_1(CONFIG_PMW33XX_3389, (PMW33XX_3389_CPI_MIN), (PMW33XX_3360_CPI_MIN)) + +struct pmw33xx_motion_burst { + uint8_t motion; + uint8_t observation; + int16_t dx; + int16_t dy; +} __attribute__((packed)); + +static inline int pmw33xx_cs_select(const struct pmw33xx_gpio_dt_spec *cs_gpio_cfg, + const uint8_t value) { + return gpio_pin_set(cs_gpio_cfg->port, cs_gpio_cfg->pin, value); +} + +static int pmw33xx_access(const struct device *dev, const uint8_t reg, uint8_t *value) { + struct pmw33xx_data *data = dev->data; + const struct pmw33xx_config *cfg = dev->config; + const struct spi_config *spi_cfg = &cfg->bus_cfg.spi_cfg->spi_conf; + const struct pmw33xx_gpio_dt_spec *cs_gpio_cfg = &cfg->bus_cfg.spi_cfg->cs_spec; + + uint8_t access[1] = {reg}; + struct spi_buf_set tx = { + .buffers = + &(struct spi_buf){ + .buf = access, + .len = 1, + }, + .count = 1, + }; + + uint8_t result[1]; + if (value != NULL) { + result[0] = *value; + } + struct spi_buf_set rx = { + .buffers = + &(struct spi_buf){ + .buf = result, + .len = 1, + }, + .count = 1, + }; + + pmw33xx_cs_select(cs_gpio_cfg, 0); + + int err = spi_write(data->bus, spi_cfg, &tx); + /* k_sleep(K_USEC(120)); // Tsrad */ + k_busy_wait(180); // Tsrad + if (err) { + pmw33xx_cs_select(cs_gpio_cfg, 1); + return err; + } + + if ((reg & PMW33XX_WR_MASK)) + err = spi_write(data->bus, spi_cfg, &rx); + else + err = spi_read(data->bus, spi_cfg, &rx); + pmw33xx_cs_select(cs_gpio_cfg, 1); + /* k_sleep(K_USEC(160)); */ + k_busy_wait(180); + if ((reg & PMW33XX_WR_MASK) == 0 && value != NULL) + *value = result[0]; + return err; +} +static int pmw33xx_read_reg(const struct device *dev, const uint8_t reg, uint8_t *value) { + return pmw33xx_access(dev, reg & PMW33XX_RD_MASK, value); +} +static int pmw33xx_write_reg(const struct device *dev, const uint8_t reg, const uint8_t value) { + uint8_t v = value; + return pmw33xx_access(dev, reg | PMW33XX_WR_MASK, &v); +} + +static int pmw33xx_write_srom(const struct device *dev) { + struct pmw33xx_data *data = dev->data; + const struct pmw33xx_config *cfg = dev->config; + const struct spi_config *spi_cfg = &cfg->bus_cfg.spi_cfg->spi_conf; + const struct pmw33xx_gpio_dt_spec *cs_gpio_cfg = &cfg->bus_cfg.spi_cfg->cs_spec; + uint8_t access[1] = {PMW33XX_REG_SROM_BURST | PMW33XX_WR_MASK}; + struct spi_buf_set tx = { + .buffers = + &(struct spi_buf){ + .buf = access, + .len = 1, + }, + .count = 1, + }; + + // 1. disable rest + pmw33xx_write_reg(dev, PMW33XX_REG_CONFIG2, 0x00); + + // 2. downlaod init cmd + pmw33xx_write_reg(dev, PMW33XX_REG_SROM_EN, PMW33XX_SROM_DWNLD_CMD); + + k_busy_wait(15); + + // 3. download start cmd + pmw33xx_write_reg(dev, PMW33XX_REG_SROM_EN, PMW33XX_SROM_DWNLD_START_CMD); + + // 4. transmit the srom firmware + pmw33xx_cs_select(cs_gpio_cfg, 0); + + int err = spi_write(data->bus, spi_cfg, &tx); + + k_busy_wait(15); + if (err) { + pmw33xx_cs_select(cs_gpio_cfg, 1); + return err; + } + + for (uint16_t i = 0; i < sizeof(SROM); i++) { + access[0] = SROM[i]; + err = spi_write(data->bus, spi_cfg, &tx); + k_busy_wait(15); + if (err) { + pmw33xx_cs_select(cs_gpio_cfg, 1); + return err; + } + } + + pmw33xx_cs_select(cs_gpio_cfg, 1); + + // 5. finish and exit + k_busy_wait(2000); // Tbexit + return err; +} + +static int pmw33xx_read_motion_burst(const struct device *dev, struct pmw33xx_motion_burst *burst) { + struct pmw33xx_data *data = dev->data; + const struct pmw33xx_config *cfg = dev->config; + const struct spi_config *spi_cfg = &cfg->bus_cfg.spi_cfg->spi_conf; + const struct pmw33xx_gpio_dt_spec *cs_gpio_cfg = &cfg->bus_cfg.spi_cfg->cs_spec; + + uint8_t access[1] = {PMW33XX_REG_BURST}; + struct spi_buf_set tx = { + .buffers = + &(struct spi_buf){ + .buf = access, + .len = 1, + }, + .count = 1, + }; + struct spi_buf_set rx = { + .buffers = + &(struct spi_buf){ + .buf = (uint8_t *)burst, + .len = sizeof(struct pmw33xx_motion_burst), + }, + .count = 1, + }; + + pmw33xx_cs_select(cs_gpio_cfg, 0); + + int err = spi_write(data->bus, spi_cfg, &tx); + if (err) { + pmw33xx_cs_select(cs_gpio_cfg, 1); + return err; + } + + // wait needed + k_busy_wait(35); // tsrad motbr + + // start reading continuosly + err = spi_read(data->bus, spi_cfg, &rx); + pmw33xx_cs_select(cs_gpio_cfg, 1); + + return err; +} + +#ifdef CONFIG_PMW33XX_TRIGGER +void pmw33xx_reset_motion(const struct device *dev) { + // reset motswk interrupt + pmw33xx_read_reg(dev, PMW33XX_REG_MOTION, NULL); +} +#endif + +#if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) +void pmw33xx_print_registers(const struct device *dev) { + LOG_DBG("print important regiter values of pmw33xx:"); + + uint8_t val; + int err; + + // pid, rid + err = pmw33xx_read_reg(dev, PMW33XX_REG_PID, &val); + if (err) { + LOG_ERR("couldn't read register 0x%x", PMW33XX_REG_PID); + } + else { + LOG_DBG("pmw33xx pid: 0x%x", val); + } + + err = pmw33xx_read_reg(dev, PMW33XX_REG_REV_ID, &val); + if (err) { + LOG_ERR("couldn't read register 0x%x", PMW33XX_REG_REV_ID); + } + else { + LOG_DBG("pmw33xx vid: 0x%x", val); + } +} +#endif + +int pmw33xx_spi_init(const struct device *dev) { + const struct pmw33xx_config *cfg = dev->config; + const struct pmw33xx_gpio_dt_spec *cs_gpio_cfg = &cfg->bus_cfg.spi_cfg->cs_spec; + + int err; + err = gpio_pin_configure(cs_gpio_cfg->port, cs_gpio_cfg->pin, GPIO_OUTPUT_ACTIVE); + if (err) { + LOG_ERR("could configure cs pin %d", err); + return -EIO; + } + return 0; +} + +static int pmw33xx_sample_fetch(const struct device *dev, enum sensor_channel chan) { + struct pmw33xx_data *data = dev->data; + struct pmw33xx_motion_burst burst; + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_POS_DX && chan != SENSOR_CHAN_POS_DY) + return -ENOTSUP; + + int err = pmw33xx_read_motion_burst(dev, &burst); + if (err) { + return err; + } + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_POS_DX) + data->dx += burst.dx; + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_POS_DY) + data->dy += burst.dy; + return 0; +} + +static int pmw33xx_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) { + struct pmw33xx_data *data = dev->data; + + switch (chan) { + case SENSOR_CHAN_POS_DX: + val->val1 = data->dx; + data->dx = 0; + break; + case SENSOR_CHAN_POS_DY: + val->val1 = data->dy; + data->dy = 0; + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static const struct sensor_driver_api pmw33xx_driver_api = { +#ifdef CONFIG_PMW33XX_TRIGGER + .trigger_set = pmw33xx_trigger_set, +#endif + // eventually implement this to allow setting cpi from the driver api maybe + // .attr_set = pmw33xx_attr_set, + .sample_fetch = pmw33xx_sample_fetch, + .channel_get = pmw33xx_channel_get, +}; + +static int pmw33xx_set_cpi(const struct device *dev, uint16_t cpi) { +#ifdef CONFIG_PMW33XX_3360 + if (cpi > PMW33XX_CPI_MIN && cpi < PMW33XX_CPI_MAX) + return pmw33xx_write_reg(dev, PMW33XX_3360_REG_CPI, + ((cpi / 100) - 1)); /* 100-12000, 100 cpi LSb */ +#elif CONFIG_PMW33XX_3389 + if (cpi > PMW33XX_CPI_MIN && cpi < PMW33XX_CPI_MAX) { + cpi /= 50; + int err = + pmw33xx_write_reg(dev, PMW33XX_3389_REG_CPI_L, cpi & 0xFF); /* 50-16000, 50 cpi LSb */ + if (err) { + return err; + } + return pmw33xx_write_reg(dev, PMW33XX_3389_REG_CPI_H, cpi >> 8); /* 50-16000, 50 cpi LSb */ + } +#endif + return -ENOTSUP; +} +static int pmw33xx_init_chip(const struct device *dev) { + const struct pmw33xx_config *const config = dev->config; + const struct pmw33xx_gpio_dt_spec *cs_gpio_cfg = &config->bus_cfg.spi_cfg->cs_spec; + + // reset spi port + pmw33xx_cs_select(cs_gpio_cfg, 1); + pmw33xx_cs_select(cs_gpio_cfg, 0); + k_sleep(K_MSEC(1)); + + // power reset + int err = pmw33xx_write_reg(dev, PMW33XX_REG_PWR_UP_RST, PMW33XX_RESET_CMD); + if (err) { + LOG_ERR("could not reset %d", err); + return -EIO; + } + k_sleep(K_MSEC(50)); + + // clear motion data (by reading motion registers from 0x02 to 0x06) + // use burst read or normal read + struct pmw33xx_motion_burst val; + pmw33xx_read_motion_burst(dev, &val); // read and throwout initial motion data + + // update fireware + err = pmw33xx_write_srom(dev); + if (err) { + LOG_ERR("could not upload srom %d", err); + return -EIO; + } + + // confirm srom running status + uint8_t srom_run = 0x0; + err = pmw33xx_read_reg(dev, PMW33XX_REG_OBSERVATION, &srom_run); + if (err) { + LOG_ERR("could not check srom status %d", err); + return -EIO; + } + if (!(srom_run & PMW33XX_SROM_RUN)) { + LOG_ERR("srom status invalid %d", srom_run); + return -EIO; + } + + // confirm firmware update by reading srom version, todo: comparison needed + uint8_t srom_id = 0x0; + err = pmw33xx_read_reg(dev, PMW33XX_REG_SROM_ID, &srom_id); + if (err) { + LOG_ERR("could not check srom id %d", err); + return -EIO; + } + LOG_INF("pmw33xx SROM firmware id: %d", srom_id); + if (srom_id != PMW3360_FIRMWARE_ID) { + LOG_ERR("srom id invalid %d", srom_id); + return -EIO; + } + + // confirm pid + uint8_t pid = 0x0; + err = pmw33xx_read_reg(dev, PMW33XX_REG_PID, &pid); + if (err) { + LOG_ERR("could not reset %d", err); + return -EIO; + } + if (pid != PMW33XX_PID) { + LOG_ERR("pid does not match expected: got (%x), expected(%x)", pid, PMW33XX_PID); + return -EIO; + } + + // enable rest + pmw33xx_write_reg(dev, PMW33XX_REG_CONFIG2, + config->disable_rest ? 0x00 : PMW33XX_RESTEN); // set rest enable + +#if IS_ENABLED(CONFIG_SENSOR_LOG_LEVEL_DBG) + pmw33xx_print_registers(dev); +#endif + + // enbale motion burst by writing something into motion_burst register, only needed once + // WARNING: no regiter reading other than position regiters after this setup + pmw33xx_write_reg(dev, PMW33XX_REG_BURST, 0x01); + + // set cpi + if (config->cpi > PMW33XX_CPI_MIN && config->cpi < PMW33XX_CPI_MAX) + return pmw33xx_set_cpi(dev, config->cpi); + + return 0; +} + +static int pmw33xx_init(const struct device *dev) { + const struct pmw33xx_config *const config = dev->config; + struct pmw33xx_data *data = dev->data; + + data->bus = device_get_binding(config->bus_name); + if (!data->bus) { + LOG_DBG("master not found: %s", log_strdup(config->bus_name)); + return -EINVAL; + } + + config->bus_init(dev); + + if (pmw33xx_init_chip(dev) < 0) { + LOG_DBG("failed to initialize chip"); + return -EIO; + } + + +#ifdef CONFIG_PMW33XX_TRIGGER + if (pmw33xx_init_interrupt(dev) < 0) { + LOG_DBG("Failed to initialize interrupt!"); + return -EIO; + } +#endif + + return 0; +} + +#define PMW33XX_DATA_SPI(n) \ + { \ + .cs_ctrl = {}, \ +.resume_interrupt = false,} + +#define PMW33XX_SPI_CFG(n) \ + (&(struct pmw33xx_spi_cfg){ \ + .spi_conf = \ + { \ + .frequency = DT_INST_PROP(n, spi_max_frequency), \ + .operation = \ + (SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA), \ + .slave = DT_INST_REG_ADDR(n), \ + }, \ + .cs_spec = PMW33XX_GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(n), cs_gpios, 0), \ + }) + +#define PMW33XX_GPIO_DT_SPEC_GET_BY_IDX(node_id, prop, idx) \ + { \ + .port = DEVICE_DT_GET(DT_GPIO_CTLR_BY_IDX(node_id, prop, idx)), \ + .pin = DT_GPIO_PIN_BY_IDX(node_id, prop, idx), \ + .dt_flags = DT_GPIO_FLAGS_BY_IDX(node_id, prop, idx), \ + } + +#define PMW33XX_CONFIG_SPI(n) \ + { \ + .bus_name = DT_INST_BUS_LABEL(n), .bus_init = pmw33xx_spi_init, \ + .bus_cfg = {.spi_cfg = PMW33XX_SPI_CFG(n)}, \ + .disable_rest = DT_INST_NODE_HAS_PROP(n, disable_rest), \ + .cpi = COND_CODE_0(DT_INST_NODE_HAS_PROP(n, cpi), (0), (DT_INST_PROP(n, cpi))) \ + COND_CODE_1(CONFIG_PMW33XX_TRIGGER, \ + (, PMW33XX_GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(n), motswk_gpios, 0)), ()) \ + } + +#define PMW33XX_INST(n) \ + static struct pmw33xx_data pmw33xx_data_##n = PMW33XX_DATA_SPI(n); \ + static const struct pmw33xx_config pmw33xx_cfg_##n = PMW33XX_CONFIG_SPI(n); \ + DEVICE_DT_INST_DEFINE(n, pmw33xx_init, device_pm_control_nop, &pmw33xx_data_##n, \ + &pmw33xx_cfg_##n, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &pmw33xx_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(PMW33XX_INST) diff --git a/app/drivers/sensor/pmw33xx/pmw33xx.h b/app/drivers/sensor/pmw33xx/pmw33xx.h new file mode 100644 index 00000000000..20bedc1bc3a --- /dev/null +++ b/app/drivers/sensor/pmw33xx/pmw33xx.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ +#ifndef ZEPHYR_DRIVERS_SENSOR_PIXART_PMW33XX_H_ +#define ZEPHYR_DRIVERS_SENSOR_PIXART_PMW33XX_H_ + +#include +#include +#include +#include +#include + +/* wr/rd mask */ +#define PMW33XX_WR_MASK 0x80 +#define PMW33XX_RD_MASK 0x7F + +/* default values */ +#define PMW33XX_3389_PID 0x47 +#define PMW33XX_3360_PID 0x42 + +// todo: different rev id for different sensor +#define PMW33XX_REV 0x01 + +/* General Registers */ +#define PMW33XX_REG_PID 0x00 +#define PMW33XX_REG_REV_ID 0x01 +#define PMW33XX_REG_PWR_UP_RST 0x3A + +/* Motion Registers */ +#define PMW33XX_REG_MOTION 0x02 +#define PMW33XX_REG_DX_L 0x03 +#define PMW33XX_REG_DX_H 0x04 +#define PMW33XX_REG_DY_L 0x05 +#define PMW33XX_REG_DY_H 0x06 + +/* Motion bits */ +#define PMW33XX_MOTION (1 << 8) +#define PMW33XX_OPMODE_RUN (0) +#define PMW33XX_OPMODE_REST1 (0b01 << 1) +#define PMW33XX_OPMODE_REST2 (0b10 << 1) +#define PMW33XX_OPMODE_REST3 (0b11 << 1) + +// todo: +#define PMW33XX_REG_BURST 0x50 +/* SROM Registers */ +#define PMW33XX_REG_SROM_EN 0x13 +#define PMW33XX_REG_SROM_ID 0x2A +#define PMW33XX_REG_SROM_BURST 0x62 + +/* SROM CMDs */ +#define PMW33XX_SROM_CRC_CMD 0x15 // self-test +#define PMW33XX_SROM_DWNLD_CMD 0x1D // init downlaod +#define PMW33XX_SROM_DWNLD_START_CMD 0x18 // start download + +/* CPI Registers */ +#define PMW33XX_3360_REG_CPI 0x0F +#define PMW33XX_3389_REG_CPI_L 0x0E +#define PMW33XX_3389_REG_CPI_H 0x0F + +/* Config Registers */ +#define PMW33XX_REG_CONFIG2 0x10 +#define PMW33XX_REG_OBSERVATION 0x24 +#define PMW33XX_REG_DOUT_L 0x25 +#define PMW33XX_REG_DOUT_H 0x26 + +/* Config2 Bits */ +#define PMW33XX_RESTEN 0x20 +#define PMW33XX_RPT_MOD 0x04 + +/* Observation Bits */ +#define PMW33XX_SROM_RUN 0x40 + +/* power up reset cmd */ +#define PMW33XX_RESET_CMD 0x5A + +/* cpi max and min values */ +#define PMW33XX_3389_CPI_MIN 50 +#define PMW33XX_3389_CPI_MAX 16000 +#define PMW33XX_3360_CPI_MIN 100 +#define PMW33XX_3360_CPI_MAX 12000 + +struct pmw33xx_gpio_dt_spec { + const struct device *port; + gpio_pin_t pin; + gpio_dt_flags_t dt_flags; +}; + +struct pmw33xx_spi_cfg { + struct spi_config spi_conf; + struct pmw33xx_gpio_dt_spec cs_spec; +}; + +union pmw33xx_bus_cfg { + struct pmw33xx_spi_cfg *spi_cfg; +}; + +struct pmw33xx_config { + char *bus_name; + int (*bus_init)(const struct device *dev); + const union pmw33xx_bus_cfg bus_cfg; + bool disable_rest; + int cpi; +#if CONFIG_PMW33XX_TRIGGER + struct pmw33xx_gpio_dt_spec motswk_spec; +#endif // CONFIG_PMW33XX_TRIGGER +}; + +struct pmw33xx_data; + +struct pmw33xx_transfer_function { + int (*read_data)(const struct device *dev, int16_t *value); +}; + +struct pmw33xx_data { + const struct device *bus; + struct spi_cs_control cs_ctrl; + + int16_t dx; + int16_t dy; + + bool resume_interrupt; + + const struct pmw33xx_transfer_function *hw_tf; + +#ifdef CONFIG_PMW33XX_TRIGGER + + struct gpio_callback motswk_gpio_cb; + const struct device *dev; + + sensor_trigger_handler_t handler; + const struct sensor_trigger *trigger; + +#if defined(CONFIG_PMW33XX_TRIGGER_OWN_THREAD) + K_THREAD_STACK_MEMBER(thread_stack, CONFIG_PMW33XX_THREAD_STACK_SIZE); + struct k_sem gpio_sem; + struct k_thread thread; +#elif defined(CONFIG_PMW33XX_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif + +#endif /* CONFIG_PMW33XX_TRIGGER */ +}; + +int pmw33xx_spi_init(const struct device *dev); +#ifdef CONFIG_PMW33XX_TRIGGER + +int pmw33xx_trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int pmw33xx_init_interrupt(const struct device *dev); + +void pmw33xx_reset_motion(const struct device *dev); +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_PIXART_PMW33XX_H_ */ diff --git a/app/drivers/sensor/pmw33xx/pmw33xx_trigger.c b/app/drivers/sensor/pmw33xx/pmw33xx_trigger.c new file mode 100644 index 00000000000..eb2efacea45 --- /dev/null +++ b/app/drivers/sensor/pmw33xx/pmw33xx_trigger.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT pixart_pmw33xx + +#include +#include +#include +#include +#include + +#include "pmw33xx.h" + +// extern struct pmw33xx_data pmw33xx_driver; + +#include +LOG_MODULE_DECLARE(PMW33XX, CONFIG_SENSOR_LOG_LEVEL); + +static inline void setup_int(const struct device *dev, bool enable) { + const struct pmw33xx_config *cfg = dev->config; + + if (gpio_pin_interrupt_configure(cfg->motswk_spec.port, cfg->motswk_spec.pin, + enable ? GPIO_INT_LEVEL_ACTIVE : GPIO_INT_DISABLE)) { + LOG_WRN("Unable to set MOTSWK GPIO interrupt"); + } +} + +static void pmw33xx_motswk_gpio_callback(const struct device *dev, struct gpio_callback *cb, + uint32_t pins) { + struct pmw33xx_data *drv_data = CONTAINER_OF(cb, struct pmw33xx_data, motswk_gpio_cb); + + LOG_DBG(""); + + // disable the interrput line + setup_int(drv_data->dev, false); + + // submit work to handler thread +#if defined(CONFIG_PMW33XX_TRIGGER_OWN_THREAD) + k_sem_give(&drv_data->gpio_sem); +#elif defined(CONFIG_PMW33XX_TRIGGER_GLOBAL_THREAD) + k_work_submit(&drv_data->work); +#endif +} + +static void pmw33xx_thread_cb(const struct device *dev) { + struct pmw33xx_data *drv_data = dev->data; + + LOG_DBG("%p", drv_data->handler); + drv_data->handler(dev, drv_data->trigger); + + // Enable once the wall/spam of interrupts is solved + if(drv_data->resume_interrupt) + setup_int(dev, true); +} + +#ifdef CONFIG_PMW33XX_TRIGGER_OWN_THREAD +static void pmw33xx_thread(int dev_ptr, int unused) { + const struct device *dev = INT_TO_POINTER(dev_ptr); + struct pmw33xx_data *drv_data = dev->data; + + ARG_UNUSED(unused); + + while (1) { + k_sem_take(&drv_data->gpio_sem, K_FOREVER); + pmw33xx_thread_cb(dev); + } +} +#endif + +#ifdef CONFIG_PMW33XX_TRIGGER_GLOBAL_THREAD +static void pmw33xx_work_cb(struct k_work *work) { + struct pmw33xx_data *drv_data = CONTAINER_OF(work, struct pmw33xx_data, work); + + LOG_DBG(" "); + + pmw33xx_thread_cb(drv_data->dev); +} +#endif + +int pmw33xx_trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) { + struct pmw33xx_data *drv_data = dev->data; + + setup_int(dev, false); + + k_msleep(5); + + drv_data->trigger = trig; + drv_data->handler = handler; + + setup_int(dev, true); + + // reset motion on int setup + // so that old position values can be overwritten by new movements + // this is needed because trigger_set is invoked after device init, thus the sensor + // already starts working when invoking trigger_set, which may have left-over positions + // the motion interrupt is not cleared according to the datasheet. + pmw33xx_reset_motion(dev); + + return 0; +} + +int pmw33xx_init_interrupt(const struct device *dev) { + struct pmw33xx_data *drv_data = dev->data; + const struct pmw33xx_config *drv_cfg = dev->config; + + drv_data->dev = dev; + + /* setup isr (interrupt service roution) */ + gpio_pin_configure(drv_cfg->motswk_spec.port, drv_cfg->motswk_spec.pin, GPIO_INPUT | drv_cfg->motswk_spec.dt_flags); + gpio_init_callback(&drv_data->motswk_gpio_cb, pmw33xx_motswk_gpio_callback, + BIT(drv_cfg->motswk_spec.pin)); + + int err = gpio_add_callback(drv_cfg->motswk_spec.port, &drv_data->motswk_gpio_cb); + if (err < 0) { + LOG_DBG("Failed to set MOTSWK callback!"); + return -EIO; + } + + // create the handler thread or work +#if defined(CONFIG_PMW33XX_TRIGGER_OWN_THREAD) + k_sem_init(&drv_data->gpio_sem, 0, UINT_MAX); + + k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_PMW33XX_THREAD_STACK_SIZE, + (k_thread_entry_t)pmw33xx_thread, dev, 0, NULL, + K_PRIO_COOP(CONFIG_PMW33XX_THREAD_PRIORITY), 0, K_NO_WAIT); +#elif defined(CONFIG_PMW33XX_TRIGGER_GLOBAL_THREAD) + k_work_init(&drv_data->work, pmw33xx_work_cb); +#endif + + return 0; +} diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index 23f2fee2806..0d79aaa85e1 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -20,3 +20,10 @@ #include #include #include +<<<<<<< HEAD +======= +#include +#include +#include +#include +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 diff --git a/app/dts/behaviors/mouse_key_press.dtsi b/app/dts/behaviors/mouse_key_press.dtsi index 975c24aaafb..4cbb35bbf84 100644 --- a/app/dts/behaviors/mouse_key_press.dtsi +++ b/app/dts/behaviors/mouse_key_press.dtsi @@ -1,8 +1,18 @@ / { +<<<<<<< HEAD behaviors { /omit-if-no-ref/ mkp: mouse_key_press { compatible = "zmk,behavior-mouse-key-press"; #binding-cells = <1>; }; }; +======= + behaviors { + /omit-if-no-ref/ mkp: behavior_mouse_key_press { + compatible = "zmk,behavior-mouse-key-press"; + label = "MOUSE_KEY_PRESS"; + #binding-cells = <1>; + }; + }; +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 }; diff --git a/app/dts/behaviors/mouse_move.dtsi b/app/dts/behaviors/mouse_move.dtsi new file mode 100644 index 00000000000..d34329c8067 --- /dev/null +++ b/app/dts/behaviors/mouse_move.dtsi @@ -0,0 +1,12 @@ +/ { + behaviors { + /omit-if-no-ref/ mmv: behavior_mouse_move { + compatible = "zmk,behavior-mouse-move"; + label = "MOUSE_MOVE"; + #binding-cells = <1>; + delay-ms = <0>; + time-to-max-speed-ms = <300>; + acceleration-exponent = <1>; + }; + }; +}; diff --git a/app/dts/behaviors/mouse_scroll.dtsi b/app/dts/behaviors/mouse_scroll.dtsi new file mode 100644 index 00000000000..fb54886dcbe --- /dev/null +++ b/app/dts/behaviors/mouse_scroll.dtsi @@ -0,0 +1,12 @@ +/ { + behaviors { + /omit-if-no-ref/ mwh: msc: behavior_mouse_scroll { + compatible = "zmk,behavior-mouse-scroll"; + label = "MOUSE_SCROLL"; + #binding-cells = <1>; + delay-ms = <0>; + time-to-max-speed-ms = <300>; + acceleration-exponent = <0>; + }; + }; +}; diff --git a/app/dts/behaviors/slider.dtsi b/app/dts/behaviors/slider.dtsi new file mode 100644 index 00000000000..15a5cea633b --- /dev/null +++ b/app/dts/behaviors/slider.dtsi @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + behaviors { + /omit-if-no-ref/ slh: behavior_slider_horizontal { + compatible = "zmk,behavior-point-device-incremental"; + label = "SLIDER_HORIZONTAL"; + #slider-binding-cells = <0>; + mode = "scroll-mode"; + flavor = "x-only"; + scale_mode = "multiplier"; + scale_factor = <10>; + }; + }; + + behaviors { + /omit-if-no-ref/ slv: behavior_slider_vertical { + compatible = "zmk,behavior-point-device-incremental"; + label = "SLIDER_VERTICAL"; + #slider-binding-cells = <0>; + mode = "scroll-mode"; + flavor = "y-only"; + scale_mode = "multiplier"; + scale_factor = <25>; + }; + }; + + behaviors { + /omit-if-no-ref/ skp: behavior_slider_key_press { + compatible = "zmk,behavior-point-device-directional"; + label = "SLIDER_KEY_PRESS"; + #slider-binding-cells = <2>; + mode = "eager-mode"; + flavor = "1-dim"; + step_size = <200>; + }; + }; + + behaviors { + /omit-if-no-ref/ skp2: behavior_slider_key_press2 { + compatible = "zmk,behavior-point-device-directional"; + label = "SLIDER_KEY_PRESS_2"; + #slider-binding-cells = <2>; + mode = "distance-mode"; + flavor = "1-dim"; + step_size = <2>; + }; + }; + + behaviors { + /omit-if-no-ref/ skp3: behavior_slider_key_press3 { + compatible = "zmk,behavior-point-device-directional"; + label = "SLIDER_KEY_PRESS_3"; + #slider-binding-cells = <2>; + mode = "time-mode"; + flavor = "1-dim"; + step_size = <2>; + }; + }; +}; + diff --git a/app/dts/behaviors/trackball.dtsi b/app/dts/behaviors/trackball.dtsi new file mode 100644 index 00000000000..1e289570c3a --- /dev/null +++ b/app/dts/behaviors/trackball.dtsi @@ -0,0 +1,133 @@ +/ { + + /* trackball move */ + behaviors { + /omit-if-no-ref/ tmv: behavior_trackball_move { + compatible = "zmk,behavior-point-device-incremental"; + label = "TRACKBALL_MOVE"; + #trackball-binding-cells = <0>; + mode = "move-mode"; + flavor = "default"; + scale_mode = "dividor"; + scale_factor = <3>; + }; + }; + + behaviors { + /omit-if-no-ref/ tmv_fine: behavior_trackball_move_fine { + compatible = "zmk,behavior-point-device-incremental"; + label = "TRACKBALL_MOVE_FINE"; + #trackball-binding-cells = <0>; + mode = "move-mode"; + flavor = "default"; + scale_mode = "dividor"; + scale_factor = <5>; + }; + }; + + behaviors { + /omit-if-no-ref/ tmv_coarse: behavior_trackball_move_coarse { + compatible = "zmk,behavior-point-device-incremental"; + label = "TRACKBALL_MOVE_COARSE"; + #trackball-binding-cells = <0>; + mode = "move-mode"; + flavor = "default"; + scale_mode = "dividor"; + scale_factor = <1>; + }; + }; + + behaviors { + /omit-if-no-ref/ tmv_x: behavior_trackball_move_x_only { + compatible = "zmk,behavior-point-device-incremental"; + label = "TRACKBALL_MOVE_X_ONLY"; + #trackball-binding-cells = <0>; + mode = "move-mode"; + flavor = "x-only"; + scale_mode = "dividor"; + scale_factor = <2>; + }; + }; + + behaviors { + /omit-if-no-ref/ tmv_y: behavior_trackball_move_y_only { + compatible = "zmk,behavior-point-device-incremental"; + label = "TRACKBALL_MOVE_Y_ONLY"; + #trackball-binding-cells = <0>; + mode = "move-mode"; + flavor = "y-only"; + scale_mode = "dividor"; + scale_factor = <2>; + }; + }; + + /* trackball scroll */ + behaviors { + /omit-if-no-ref/ tsl: behavior_trackball_scroll { + compatible = "zmk,behavior-point-device-incremental"; + label = "TRACKBALL_SCROLL"; + #trackball-binding-cells = <0>; + mode = "scroll-mode"; + flavor = "default"; + scale_mode = "dividor"; + scale_factor = <5>; + }; + }; + + behaviors { + /omit-if-no-ref/ tsl_fine: behavior_trackball_scroll_fine { + compatible = "zmk,behavior-point-device-incremental"; + label = "TRACKBALL_SCROLL_FINE"; + #trackball-binding-cells = <0>; + mode = "scroll-mode"; + flavor = "default"; + scale_mode = "dividor"; + scale_factor = <50>; + }; + }; + + behaviors { + /omit-if-no-ref/ tsl_coarse: behavior_trackball_scroll_coarse { + compatible = "zmk,behavior-point-device-incremental"; + label = "TRACKBALL_SCROLL_COARSE"; + #trackball-binding-cells = <0>; + mode = "scroll-mode"; + flavor = "default"; + scale_mode = "dividor"; + scale_factor = <5>; + }; + }; + /* trackball key press */ + behaviors { + /omit-if-no-ref/ tkp: behavior_trackball_key_press { + compatible = "zmk,behavior-point-device-directional"; + label = "TRACKBALL_KEY_PRESS"; + #trackball-binding-cells = <4>; + mode = "distance-mode"; + flavor = "2-dim"; + step_size = <250>; + }; + }; + + behaviors { + /omit-if-no-ref/ tkp_fast: behavior_trackball_key_press { + compatible = "zmk,behavior-point-device-directional"; + label = "TRACKBALL_KEY_PRESS"; + #trackball-binding-cells = <4>; + mode = "distance-mode"; + flavor = "2-dim"; + step_size = <100>; + }; + }; + + behaviors { + /omit-if-no-ref/ tkp_dt: behavior_trackball_key_press2 { + compatible = "zmk,behavior-point-device-directional"; + label = "TRACKBALL_KEY_PRESS_2"; + #trackball-binding-cells = <4>; + mode = "time-mode"; + flavor = "2-dim"; + step_size = <200>; + }; + }; +}; diff --git a/app/dts/bindings/behaviors/zmk,behavior-mod-morph.yaml b/app/dts/bindings/behaviors/zmk,behavior-mod-morph.yaml index 20235d045f7..f90ad4e3fbb 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-mod-morph.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-mod-morph.yaml @@ -14,6 +14,10 @@ properties: mods: type: int required: true +<<<<<<< HEAD keep-mods: +======= + masked_mods: +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 type: int required: false diff --git a/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml b/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml new file mode 100644 index 00000000000..73ec34ec2db --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml @@ -0,0 +1,13 @@ +description: Mouse move + +compatible: "zmk,behavior-mouse-move" + +include: one_param.yaml + +properties: + delay-ms: + type: int + time-to-max-speed-ms: + type: int + acceleration-exponent: + type: int diff --git a/app/dts/bindings/behaviors/zmk,behavior-mouse-scroll.yaml b/app/dts/bindings/behaviors/zmk,behavior-mouse-scroll.yaml new file mode 100644 index 00000000000..5a932bc5904 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-mouse-scroll.yaml @@ -0,0 +1,13 @@ +description: Mouse scroll + +compatible: "zmk,behavior-mouse-scroll" + +include: one_param.yaml + +properties: + delay-ms: + type: int + time-to-max-speed-ms: + type: int + acceleration-exponent: + type: int diff --git a/app/dts/bindings/behaviors/zmk,behavior-point-device-directional.yaml b/app/dts/bindings/behaviors/zmk,behavior-point-device-directional.yaml new file mode 100644 index 00000000000..3fbf496cc7c --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-point-device-directional.yaml @@ -0,0 +1,48 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Directional behavior of point devices + +compatible: "zmk,behavior-point-device-directional" + +properties: + label: + type: string + required: true + "#slider-binding-cells": + type: int + required: false + const: 2 + "#trackball-binding-cells": + type: int + required: false + const: 4 + mode: + type: string + required: false + default: "distance-mode" + enum: + - "time-mode" + - "distance-mode" + - "eager-mode" + flavor: + type: string + required: false + default: "2-dim" + enum: + - "1-dim" + - "2-dim" + step_size: + type: int + default: 10 + description: the threshold to determine one step, unit is ms in time-mode + +slider-binding-cells: + - param1 + - param2 + +trackball-binding-cells: + - param1 + - param2 + - param3 + - param4 diff --git a/app/dts/bindings/behaviors/zmk,behavior-point-device-incremental.yaml b/app/dts/bindings/behaviors/zmk,behavior-point-device-incremental.yaml new file mode 100644 index 00000000000..6d2adb8d8ef --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-point-device-incremental.yaml @@ -0,0 +1,49 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Scroll and move behavior of point devices + +compatible: "zmk,behavior-point-device-incremental" + +properties: + label: + type: string + required: true + "#slider-binding-cells": + type: int + required: false + const: 0 + "#trackball-binding-cells": + type: int + required: false + const: 0 + mode: + type: string + required: false + default: "move-mode" + enum: + - "move-mode" + - "scroll-mode" + flavor: + type: string + required: false + default: "default" + enum: + - "default" + - "swap" + - "x-only" + - "y-only" + scale_mode: + type: string + required: false + default: "multiplier" + enum: + - "multiplier" + - "dividor" + scale_factor: + type: int + required: false + default: 10 + smoothing: + type: boolean + description: Add interleaved delta and inertial delta diff --git a/app/dts/bindings/zmk,keymap-sliders.yaml b/app/dts/bindings/zmk,keymap-sliders.yaml new file mode 100644 index 00000000000..0cfda72c5fa --- /dev/null +++ b/app/dts/bindings/zmk,keymap-sliders.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: | + Collection of sliders bound in the keymap layers, the layer key is used to switch slider mode. + +compatible: "zmk,keymap-sliders" + +properties: + sliders: + type: phandles + required: true diff --git a/app/dts/bindings/zmk,keymap-trackballs.yaml b/app/dts/bindings/zmk,keymap-trackballs.yaml new file mode 100644 index 00000000000..cffb527d71d --- /dev/null +++ b/app/dts/bindings/zmk,keymap-trackballs.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: | + Collection of trackballs bound in the keymap layers, the layer key is used to switch working mode. + +compatible: "zmk,keymap-trackballs" + +properties: + trackballs: + type: phandles + required: true diff --git a/app/dts/bindings/zmk,keymap.yaml b/app/dts/bindings/zmk,keymap.yaml index 4c675d21237..7902cd84011 100644 --- a/app/dts/bindings/zmk,keymap.yaml +++ b/app/dts/bindings/zmk,keymap.yaml @@ -17,9 +17,21 @@ child-binding: sensor-bindings: type: phandle-array required: false +<<<<<<< HEAD label: type: string required: false deprecated: true description: Deprecated. Use "name" instead. +======= + slider-bindings: + type: phandle-array + required: false + trackball-bindings: + type: phandle-array + required: false + joystick-bindings: + type: phandle-array + required: false +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 diff --git a/app/include/drivers/behavior.h b/app/include/drivers/behavior.h index 3936da5e4be..c7eb1c0ebcc 100644 --- a/app/include/drivers/behavior.h +++ b/app/include/drivers/behavior.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -30,6 +31,7 @@ enum behavior_sensor_binding_process_mode { typedef int (*behavior_keymap_binding_callback_t)(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event); +<<<<<<< HEAD typedef int (*behavior_sensor_keymap_binding_process_callback_t)( struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, enum behavior_sensor_binding_process_mode mode); @@ -37,6 +39,13 @@ typedef int (*behavior_sensor_keymap_binding_accept_data_callback_t)( struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, const struct zmk_sensor_config *sensor_config, size_t channel_data_size, const struct zmk_sensor_channel_data channel_data[channel_data_size]); +======= +typedef int (*behavior_sensor_keymap_binding_callback_t)(struct zmk_behavior_binding *binding, + const struct sensor_value value, + int64_t timestamp); +typedef int (*behavior_pd_keymap_binding_callback_t)(struct zmk_behavior_binding *binding, + int16_t dx, int16_t dy, int dt, int64_t timestamp); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 enum behavior_locality { BEHAVIOR_LOCALITY_CENTRAL, @@ -49,8 +58,13 @@ __subsystem struct behavior_driver_api { behavior_keymap_binding_callback_t binding_convert_central_state_dependent_params; behavior_keymap_binding_callback_t binding_pressed; behavior_keymap_binding_callback_t binding_released; +<<<<<<< HEAD behavior_sensor_keymap_binding_accept_data_callback_t sensor_binding_accept_data; behavior_sensor_keymap_binding_process_callback_t sensor_binding_process; +======= + behavior_sensor_keymap_binding_callback_t sensor_binding_triggered; + behavior_pd_keymap_binding_callback_t pd_binding_triggered; +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 }; /** * @endcond @@ -209,6 +223,7 @@ static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_bi * @retval 0 If successful. * @retval Negative errno code if failure. */ +<<<<<<< HEAD __syscall int behavior_sensor_keymap_binding_accept_data( struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, const struct zmk_sensor_config *sensor_config, size_t channel_data_size, @@ -219,6 +234,15 @@ static inline int z_impl_behavior_sensor_keymap_binding_accept_data( const struct zmk_sensor_config *sensor_config, size_t channel_data_size, const struct zmk_sensor_channel_data *channel_data) { const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); +======= +__syscall int behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *binding, + const struct sensor_value value, + int64_t timestamp); + +static inline int z_impl_behavior_sensor_keymap_binding_triggered( + struct zmk_behavior_binding *binding, const struct sensor_value value, int64_t timestamp) { + const struct device *dev = device_get_binding(binding->behavior_dev); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 if (dev == NULL) { return -EINVAL; @@ -230,6 +254,7 @@ static inline int z_impl_behavior_sensor_keymap_binding_accept_data( return -ENOTSUP; } +<<<<<<< HEAD return api->sensor_binding_accept_data(binding, event, sensor_config, channel_data_size, channel_data); } @@ -267,8 +292,42 @@ z_impl_behavior_sensor_keymap_binding_process(struct zmk_behavior_binding *bindi } return api->sensor_binding_process(binding, event, mode); +======= + return api->sensor_binding_triggered(binding, value, timestamp); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } +/** + * @brief Handle the a point device keymap binding being triggered + * @param binding Pointer to the data structure for the behavior binding. + * @param sensor Pointer to the sensor device structure for the sensor driver instance. + * @param param1 User parameter specified at time of behavior binding. + * @param param2 User parameter specified at time of behavior binding. + * + * @retval 0 If successful. + * @retval Negative errno code if failure. + */ +__syscall int behavior_pd_keymap_binding_triggered(struct zmk_behavior_binding *binding, + int16_t dx, int16_t dy, int dt, int64_t timestamp); + +static inline int z_impl_behavior_pd_keymap_binding_triggered(struct zmk_behavior_binding *binding, + int16_t dx, int16_t dy, int dt, + int64_t timestamp + ) { + const struct device *dev = device_get_binding(binding->behavior_dev); + + if (dev == NULL) { + return -EINVAL; + } + + const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; + + if (api->pd_binding_triggered == NULL) { + return -ENOTSUP; + } + + return api->pd_binding_triggered(binding, dx, dy, dt, timestamp); +} /** * @} */ diff --git a/app/include/drivers/kscan_wrapper.h b/app/include/drivers/kscan_wrapper.h new file mode 100644 index 00000000000..5d8672ec595 --- /dev/null +++ b/app/include/drivers/kscan_wrapper.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + typedef void (*kscan_slider_callback_t)(const struct device *dev, + int16_t dPos, int dT); + typedef void (*kscan_slider_config_t)(const struct device *dev, + kscan_slider_callback_t callback, + int id); + + struct kscan_slider_api { + struct kscan_driver_api kscan_api; + kscan_slider_config_t slider_config; + }; + + void kscan_slider_config(const struct device *dev, + kscan_slider_callback_t callback, + int id); + +#ifdef __cplusplus +} +#endif diff --git a/app/include/drivers/slider.h b/app/include/drivers/slider.h new file mode 100644 index 00000000000..4d414c6bc7c --- /dev/null +++ b/app/include/drivers/slider.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/** + * @file slider.h + * + * @brief Common header file for all devices supporting slide manueover + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + struct slider_data { + kscan_slider_callback_t callback; // callback to process when slider mode is enabled + uint8_t id; // needed when multiple sliders exist to get the corresponding behavior + uint8_t step; + int16_t delta_position; + int16_t acc_position; + int64_t pre_ts; + int delta_time; + }; + +#ifdef __cplusplus +} + +#endif diff --git a/app/include/dt-bindings/zmk/mouse.h b/app/include/dt-bindings/zmk/mouse.h index 582518aff7e..e2d6258ff22 100644 --- a/app/include/dt-bindings/zmk/mouse.h +++ b/app/include/dt-bindings/zmk/mouse.h @@ -5,6 +5,7 @@ */ #pragma once +<<<<<<< HEAD #include /* Mouse press behavior */ @@ -22,3 +23,53 @@ #define MB4 BIT(3) #define MB5 BIT(4) +======= +/* Mouse press behavior */ +/* Left click */ +#define MB1 (0x01) +#define LCLK (MB1) + +/* Right click */ +#define MB2 (0x02) +#define RCLK (MB2) + +/* Middle click */ +#define MB3 (0x04) +#define MCLK (MB3) + +#define MB4 (0x08) + +#define MB5 (0x10) + +#define MB6 (0x20) + +#define MB7 (0x40) + +#define MB8 (0x80) + +/* Mouse move behavior */ +#define MOVE_VERT(vert) ((vert)&0xFFFF) +#define MOVE_VERT_DECODE(encoded) (int16_t)((encoded)&0x0000FFFF) +#define MOVE_HOR(hor) (((hor)&0xFFFF) << 16) +#define MOVE_HOR_DECODE(encoded) (int16_t)(((encoded)&0xFFFF0000) >> 16) + +#define MOVE(hor, vert) (MOVE_HOR(hor) + MOVE_VERT(vert)) + +#define MOVE_UP MOVE_VERT(-600) +#define MOVE_DOWN MOVE_VERT(600) +#define MOVE_LEFT MOVE_HOR(-600) +#define MOVE_RIGHT MOVE_HOR(600) + +/* Mouse scroll behavior */ +#define SCROLL_VERT(vert) ((vert)&0xFFFF) +#define SCROLL_VERT_DECODE(encoded) (int16_t)((encoded)&0x0000FFFF) +#define SCROLL_HOR(hor) (((hor)&0xFFFF) << 16) +#define SCROLL_HOR_DECODE(encoded) (int16_t)(((encoded)&0xFFFF0000) >> 16) + +#define SCROLL(hor, vert) (SCROLL_HOR(hor) + SCROLL_VERT(vert)) + +#define SCROLL_UP SCROLL_VERT(10) +#define SCROLL_DOWN SCROLL_VERT(-10) +#define SCROLL_LEFT SCROLL_HOR(-10) +#define SCROLL_RIGHT SCROLL_HOR(10) +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 diff --git a/app/include/zmk/behavior.h b/app/include/zmk/behavior.h index ab95fd8e728..1cc1beb2d33 100644 --- a/app/include/zmk/behavior.h +++ b/app/include/zmk/behavior.h @@ -15,6 +15,8 @@ struct zmk_behavior_binding { char *behavior_dev; uint32_t param1; uint32_t param2; + uint32_t param3; + uint32_t param4; }; struct zmk_behavior_binding_event { @@ -22,6 +24,7 @@ struct zmk_behavior_binding_event { uint32_t position; int64_t timestamp; }; +<<<<<<< HEAD /** * @brief Get a const struct device* for a behavior from its @p name field. @@ -36,3 +39,5 @@ struct zmk_behavior_binding_event { * unrelated node which shares the same name as a behavior. */ const struct device *zmk_behavior_get_binding(const char *name); +======= +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 diff --git a/app/include/zmk/endpoints.h b/app/include/zmk/endpoints.h index 4a2245f5185..b45fe7cb3aa 100644 --- a/app/include/zmk/endpoints.h +++ b/app/include/zmk/endpoints.h @@ -71,7 +71,11 @@ struct zmk_endpoint_instance zmk_endpoints_selected(void); bool zmk_endpoints_preferred_transport_is_active(); int zmk_endpoints_send_report(uint16_t usage_page); +<<<<<<< HEAD #if IS_ENABLED(CONFIG_ZMK_MOUSE) int zmk_endpoints_send_mouse_report(); #endif // IS_ENABLE(CONFIG_ZMK_MOUSE) +======= +int zmk_endpoints_send_mouse_report(); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 diff --git a/app/include/zmk/events/mouse_button_state_changed.h b/app/include/zmk/events/mouse_button_state_changed.h index ff3ccecd714..6d103397e1a 100644 --- a/app/include/zmk/events/mouse_button_state_changed.h +++ b/app/include/zmk/events/mouse_button_state_changed.h @@ -7,6 +7,10 @@ #pragma once +<<<<<<< HEAD +======= +#include +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 #include #include #include @@ -19,8 +23,14 @@ struct zmk_mouse_button_state_changed { ZMK_EVENT_DECLARE(zmk_mouse_button_state_changed); +<<<<<<< HEAD static inline int raise_zmk_mouse_button_state_changed_from_encoded(uint32_t encoded, bool pressed, int64_t timestamp) { return raise_zmk_mouse_button_state_changed((struct zmk_mouse_button_state_changed){ +======= +static inline struct zmk_mouse_button_state_changed_event * +zmk_mouse_button_state_changed_from_encoded(uint32_t encoded, bool pressed, int64_t timestamp) { + return new_zmk_mouse_button_state_changed((struct zmk_mouse_button_state_changed){ +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 .buttons = ZMK_HID_USAGE_ID(encoded), .state = pressed, .timestamp = timestamp}); } diff --git a/app/include/zmk/events/mouse_move_state_changed.h b/app/include/zmk/events/mouse_move_state_changed.h new file mode 100644 index 00000000000..8866f81d4e8 --- /dev/null +++ b/app/include/zmk/events/mouse_move_state_changed.h @@ -0,0 +1,33 @@ + +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +struct zmk_mouse_move_state_changed { + struct vector2d max_speed; + struct mouse_config config; + bool state; + int64_t timestamp; +}; + +ZMK_EVENT_DECLARE(zmk_mouse_move_state_changed); + +static inline struct zmk_mouse_move_state_changed_event * +zmk_mouse_move_state_changed_from_encoded(uint32_t encoded, struct mouse_config config, + bool pressed, int64_t timestamp) { + struct vector2d max_speed = (struct vector2d){ + .x = MOVE_HOR_DECODE(encoded), + .y = MOVE_VERT_DECODE(encoded), + }; + + return new_zmk_mouse_move_state_changed((struct zmk_mouse_move_state_changed){ + .max_speed = max_speed, .config = config, .state = pressed, .timestamp = timestamp}); +} diff --git a/app/include/zmk/events/mouse_scroll_state_changed.h b/app/include/zmk/events/mouse_scroll_state_changed.h new file mode 100644 index 00000000000..fa60e8a7422 --- /dev/null +++ b/app/include/zmk/events/mouse_scroll_state_changed.h @@ -0,0 +1,34 @@ + +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include +#include + +struct zmk_mouse_scroll_state_changed { + struct vector2d max_speed; + struct mouse_config config; + bool state; + int64_t timestamp; +}; + +ZMK_EVENT_DECLARE(zmk_mouse_scroll_state_changed); + +static inline struct zmk_mouse_scroll_state_changed_event * +zmk_mouse_scroll_state_changed_from_encoded(uint32_t encoded, struct mouse_config config, + bool pressed, int64_t timestamp) { + struct vector2d max_speed = (struct vector2d){ + .x = SCROLL_HOR_DECODE(encoded), + .y = SCROLL_VERT_DECODE(encoded), + }; + + return new_zmk_mouse_scroll_state_changed((struct zmk_mouse_scroll_state_changed){ + .max_speed = max_speed, .config = config, .state = pressed, .timestamp = timestamp}); +} diff --git a/app/include/zmk/events/mouse_tick.h b/app/include/zmk/events/mouse_tick.h new file mode 100644 index 00000000000..c75b9b4f86e --- /dev/null +++ b/app/include/zmk/events/mouse_tick.h @@ -0,0 +1,39 @@ + +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include +#include + +struct zmk_mouse_tick { + struct vector2d max_move; + struct vector2d max_scroll; + struct mouse_config move_config; + struct mouse_config scroll_config; + int64_t *start_time; + int64_t timestamp; +}; + +ZMK_EVENT_DECLARE(zmk_mouse_tick); + +static inline struct zmk_mouse_tick_event *zmk_mouse_tick(struct vector2d max_move, + struct vector2d max_scroll, + struct mouse_config move_config, + struct mouse_config scroll_config, + int64_t *movement_start) { + return new_zmk_mouse_tick((struct zmk_mouse_tick){ + .max_move = max_move, + .max_scroll = max_scroll, + .move_config = move_config, + .scroll_config = scroll_config, + .start_time = movement_start, + .timestamp = k_uptime_get(), + }); +} diff --git a/app/include/zmk/events/pd_position_state_changed.h b/app/include/zmk/events/pd_position_state_changed.h new file mode 100644 index 00000000000..ed47dfa5ef5 --- /dev/null +++ b/app/include/zmk/events/pd_position_state_changed.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +struct zmk_pd_position_state_changed { + int16_t x; + int16_t y; +}; + +ZMK_EVENT_DECLARE(zmk_pd_position_state_changed); diff --git a/app/include/zmk/events/pd_raw_event.h b/app/include/zmk/events/pd_raw_event.h new file mode 100644 index 00000000000..6b81a9df326 --- /dev/null +++ b/app/include/zmk/events/pd_raw_event.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +struct zmk_pd_raw_event { + enum pd_type type; + uint8_t id; + int16_t dx; + int16_t dy; + int dt; // in ms + int64_t update_time; // in ms +}; + +ZMK_EVENT_DECLARE(zmk_pd_raw_event); diff --git a/app/include/zmk/events/pd_scroll_state_changed.h b/app/include/zmk/events/pd_scroll_state_changed.h new file mode 100644 index 00000000000..4ede6e0698b --- /dev/null +++ b/app/include/zmk/events/pd_scroll_state_changed.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +struct zmk_pd_scroll_state_changed { + int16_t x; + int16_t y; +}; + +ZMK_EVENT_DECLARE(zmk_pd_scroll_state_changed); diff --git a/app/include/zmk/events/sensor_event.h b/app/include/zmk/events/sensor_event.h index f6d23ac71d9..0dfd4d2faf4 100644 --- a/app/include/zmk/events/sensor_event.h +++ b/app/include/zmk/events/sensor_event.h @@ -6,9 +6,14 @@ #pragma once +<<<<<<< HEAD #include #include +======= +#include +#include +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 #include #include @@ -16,9 +21,14 @@ #define ZMK_SENSOR_EVENT_MAX_CHANNELS 1 struct zmk_sensor_event { +<<<<<<< HEAD size_t channel_data_size; struct zmk_sensor_channel_data channel_data[ZMK_SENSOR_EVENT_MAX_CHANNELS]; +======= + uint8_t sensor_number; + struct sensor_value value; +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 int64_t timestamp; uint8_t sensor_index; diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index d1d3b7d47db..b2e7fbcd32e 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -6,6 +6,7 @@ #pragma once +<<<<<<< HEAD #include #include @@ -14,6 +15,14 @@ #include #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) +======= +#include +//#include +#include + +#include +#include +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 #include #include @@ -21,6 +30,7 @@ #define ZMK_HID_KEYBOARD_NKRO_MAX_USAGE HID_USAGE_KEY_KEYBOARD_LANG8 #else #define ZMK_HID_KEYBOARD_NKRO_MAX_USAGE HID_USAGE_KEY_KEYPAD_EQUAL +<<<<<<< HEAD #endif #define ZMK_HID_MOUSE_NUM_BUTTONS 0x05 @@ -58,6 +68,10 @@ #define ZMK_HID_REPORT_ID_LEDS 0x01 #define ZMK_HID_REPORT_ID_CONSUMER 0x02 #define ZMK_HID_REPORT_ID_MOUSE 0x03 +======= + +#define COLLECTION_REPORT 0x03 +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 static const uint8_t zmk_hid_report_desc[] = { HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP), @@ -139,8 +153,89 @@ static const uint8_t zmk_hid_report_desc[] = { #else #error "A proper consumer HID report usage range must be selected" #endif + /* REPORT_COUNT (CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE) */ HID_REPORT_COUNT(CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE), +<<<<<<< HEAD HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_ARRAY | ZMK_HID_MAIN_VAL_ABS), +======= + HID_INPUT(0x00), + /* END COLLECTION */ + HID_END_COLLECTION, + + /* USAGE_PAGE (Generic Desktop) */ + HID_USAGE_PAGE(HID_USAGE_GD), + /* USAGE (Mouse) */ + HID_USAGE(HID_USAGE_GD_MOUSE), + /* COLLECTION (Application) */ + HID_COLLECTION(HID_COLLECTION_APPLICATION), + /* REPORT ID (4) */ + HID_REPORT_ID(0x04), + /* USAGE (Pointer) */ + HID_USAGE(HID_USAGE_GD_POINTER), + /* COLLECTION (Physical) */ + HID_COLLECTION(HID_COLLECTION_PHYSICAL), + /* USAGE_PAGE (Button) */ + HID_USAGE_PAGE(HID_USAGE_BUTTON), + /* USAGE_MINIMUM (0x1) (button 1?) */ + HID_USAGE_MIN8(0x01), + /* USAGE_MAXIMUM (0x10) (button 5? Buttons up to 8 still work) */ + HID_USAGE_MAX8(0x10), + /* LOGICAL_MINIMUM (0) */ + HID_LOGICAL_MIN8(0x00), + /* LOGICAL_MAXIMUM (1) */ + HID_LOGICAL_MAX8(0x01), + /* REPORT_SIZE (1) */ + HID_REPORT_SIZE(0x01), + /* REPORT_COUNT (16) */ + HID_REPORT_COUNT(0x10), + /* INPUT (Data,Var,Abs) */ + HID_INPUT(0x02), + /* USAGE_PAGE (Generic Desktop) */ + HID_USAGE_PAGE(HID_USAGE_GD), + /* LOGICAL_MINIMUM (-32767) */ + HID_LOGICAL_MIN16(0x01, 0x80), + /* LOGICAL_MAXIMUM (32767) */ + HID_LOGICAL_MAX16(0xFF, 0x7F), + /* REPORT_SIZE (16) */ + HID_REPORT_SIZE(0x10), + /* REPORT_COUNT (2) */ + HID_REPORT_COUNT(0x02), + /* USAGE (X) */ // Vertical scroll + HID_USAGE(HID_USAGE_GD_X), + /* USAGE (Y) */ + HID_USAGE(HID_USAGE_GD_Y), + /* Input (Data,Var,Rel) */ + HID_INPUT(0x06), + /* LOGICAL_MINIMUM (-127) */ + HID_LOGICAL_MIN8(0x81), + /* LOGICAL_MAXIMUM (127) */ + HID_LOGICAL_MAX8(0x7F), + /* REPORT_SIZE (8) */ + HID_REPORT_SIZE(0x08), + /* REPORT_COUNT (1) */ + HID_REPORT_COUNT(0x01), + /* USAGE (Wheel) */ + HID_USAGE(HID_USAGE_GD_WHEEL), + /* Input (Data,Var,Rel) */ + HID_INPUT(0x06), + /* USAGE_PAGE (Consumer) */ // Horizontal scroll + HID_USAGE_PAGE(HID_USAGE_CONSUMER), + /* USAGE (AC Pan) */ + 0x0A, + 0x38, + 0x02, + /* LOGICAL_MINIMUM (-127) */ + HID_LOGICAL_MIN8(0x81), + /* LOGICAL_MAXIMUM (127) */ + HID_LOGICAL_MAX8(0x7F), + /* REPORT_COUNT (1) */ + HID_REPORT_COUNT(0x01), + /* Input (Data,Var,Rel) */ + HID_INPUT(0x06), + /* END COLLECTION */ + HID_END_COLLECTION, + /* END COLLECTION */ +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 HID_END_COLLECTION, #if IS_ENABLED(CONFIG_ZMK_MOUSE) @@ -237,12 +332,21 @@ struct zmk_hid_consumer_report { struct zmk_hid_consumer_report_body body; } __packed; +<<<<<<< HEAD #if IS_ENABLED(CONFIG_ZMK_MOUSE) struct zmk_hid_mouse_report_body { zmk_mouse_button_flags_t buttons; int8_t d_x; int8_t d_y; int8_t d_wheel; +======= +struct zmk_hid_mouse_report_body { + zmk_mouse_button_flags_t buttons; + int16_t x; + int16_t y; + int8_t scroll_y; + int8_t scroll_x; +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } __packed; struct zmk_hid_mouse_report { @@ -250,9 +354,13 @@ struct zmk_hid_mouse_report { struct zmk_hid_mouse_report_body body; } __packed; +<<<<<<< HEAD #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) zmk_mod_flags_t zmk_hid_get_explicit_mods(void); +======= +zmk_mod_flags_t zmk_hid_get_explicit_mods(); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 int zmk_hid_register_mod(zmk_mod_t modifier); int zmk_hid_unregister_mod(zmk_mod_t modifier); bool zmk_hid_mod_is_pressed(zmk_mod_t modifier); @@ -264,6 +372,9 @@ int zmk_hid_implicit_modifiers_release(void); int zmk_hid_masked_modifiers_set(zmk_mod_flags_t masked_modifiers); int zmk_hid_masked_modifiers_clear(void); +int zmk_hid_masked_modifiers_set(zmk_mod_flags_t masked_modifiers); +int zmk_hid_masked_modifiers_clear(); + int zmk_hid_keyboard_press(zmk_key_t key); int zmk_hid_keyboard_release(zmk_key_t key); void zmk_hid_keyboard_clear(void); @@ -278,11 +389,15 @@ int zmk_hid_press(uint32_t usage); int zmk_hid_release(uint32_t usage); bool zmk_hid_is_pressed(uint32_t usage); +<<<<<<< HEAD #if IS_ENABLED(CONFIG_ZMK_MOUSE) +======= +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 int zmk_hid_mouse_button_press(zmk_mouse_button_t button); int zmk_hid_mouse_button_release(zmk_mouse_button_t button); int zmk_hid_mouse_buttons_press(zmk_mouse_button_flags_t buttons); int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons); +<<<<<<< HEAD void zmk_hid_mouse_clear(void); #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) @@ -296,3 +411,14 @@ zmk_hid_boot_report_t *zmk_hid_get_boot_report(); #if IS_ENABLED(CONFIG_ZMK_MOUSE) struct zmk_hid_mouse_report *zmk_hid_get_mouse_report(); #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) +======= +void zmk_hid_mouse_movement_set(int16_t x, int16_t y); +void zmk_hid_mouse_scroll_set(int8_t x, int8_t y); +void zmk_hid_mouse_movement_update(int16_t x, int16_t y); +void zmk_hid_mouse_scroll_update(int8_t x, int8_t y); +void zmk_hid_mouse_clear(); + +struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report(); +struct zmk_hid_consumer_report *zmk_hid_get_consumer_report(); +struct zmk_hid_mouse_report *zmk_hid_get_mouse_report(); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 diff --git a/app/include/zmk/hog.h b/app/include/zmk/hog.h index eb6e653f772..cc492b9f74c 100644 --- a/app/include/zmk/hog.h +++ b/app/include/zmk/hog.h @@ -11,7 +11,12 @@ int zmk_hog_send_keyboard_report(struct zmk_hid_keyboard_report_body *body); int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *body); +<<<<<<< HEAD #if IS_ENABLED(CONFIG_ZMK_MOUSE) int zmk_hog_send_mouse_report(struct zmk_hid_mouse_report_body *body); #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) +======= +int zmk_hog_send_mouse_report(struct zmk_hid_mouse_report_body *body); +int zmk_hog_send_mouse_report_direct(struct zmk_hid_mouse_report_body *body); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 diff --git a/app/include/zmk/keymap.h b/app/include/zmk/keymap.h index 0d7dbaf33b3..17eb2c55283 100644 --- a/app/include/zmk/keymap.h +++ b/app/include/zmk/keymap.h @@ -20,6 +20,8 @@ bool zmk_keymap_layer_active(uint8_t layer); uint8_t zmk_keymap_highest_layer_active(void); int zmk_keymap_layer_activate(uint8_t layer); int zmk_keymap_layer_deactivate(uint8_t layer); +int zmk_keymap_layer_activate_noevent(uint8_t layer); +int zmk_keymap_layer_deactivate_noevent(uint8_t layer); int zmk_keymap_layer_toggle(uint8_t layer); int zmk_keymap_layer_to(uint8_t layer); const char *zmk_keymap_layer_name(uint8_t layer); diff --git a/app/include/zmk/mouse.h b/app/include/zmk/mouse.h index d873f15689a..776874fbcd1 100644 --- a/app/include/zmk/mouse.h +++ b/app/include/zmk/mouse.h @@ -6,7 +6,32 @@ #pragma once +<<<<<<< HEAD #include typedef uint8_t zmk_mouse_button_flags_t; typedef uint16_t zmk_mouse_button_t; +======= +#include +#include + +typedef uint16_t zmk_mouse_button_flags_t; +typedef uint16_t zmk_mouse_button_t; + +struct mouse_config { + int delay_ms; + int time_to_max_speed_ms; + // acceleration exponent 0: uniform speed + // acceleration exponent 1: uniform acceleration + // acceleration exponent 2: uniform jerk + int acceleration_exponent; +}; + +struct vector2d { + float x; + float y; +}; + +struct k_work_q *zmk_mouse_work_q(); +int zmk_mouse_init(); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 diff --git a/app/include/zmk/point_device.h b/app/include/zmk/point_device.h new file mode 100644 index 00000000000..1bc51f01b2b --- /dev/null +++ b/app/include/zmk/point_device.h @@ -0,0 +1,10 @@ +#pragma once + +enum pd_type { + SLIDER, + TRACKBALL, + JOYSTICK +}; + +struct k_work_q *zmk_pd_work_q(); +int zmk_pd_init(); diff --git a/app/include/zmk/sensors.h b/app/include/zmk/sensors.h index 1919d4ce647..dd2f8ae2e78 100644 --- a/app/include/zmk/sensors.h +++ b/app/include/zmk/sensors.h @@ -12,6 +12,7 @@ #define ZMK_KEYMAP_HAS_SENSORS DT_NODE_HAS_STATUS(ZMK_KEYMAP_SENSORS_NODE, okay) #define ZMK_KEYMAP_SENSORS_BY_IDX(idx) DT_PHANDLE_BY_IDX(ZMK_KEYMAP_SENSORS_NODE, sensors, idx) +<<<<<<< HEAD #if ZMK_KEYMAP_HAS_SENSORS #define ZMK_KEYMAP_SENSORS_LEN DT_PROP_LEN(ZMK_KEYMAP_SENSORS_NODE, sensors) #else @@ -30,3 +31,11 @@ struct zmk_sensor_channel_data { struct sensor_value value; enum sensor_channel channel; } __packed; +======= +#include + +enum { + // Cirque Pinnacle Glide Extend + SENSOR_ATTR_PINNACLE_GE = SENSOR_ATTR_PRIV_START, +}; +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 diff --git a/app/include/zmk/sliders.h b/app/include/zmk/sliders.h new file mode 100644 index 00000000000..dd9fddc4ee7 --- /dev/null +++ b/app/include/zmk/sliders.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#define ZMK_KEYMAP_SLIDERS_NODE DT_INST(0, zmk_keymap_sliders) +#define ZMK_KEYMAP_HAS_SLIDERS DT_NODE_HAS_STATUS(ZMK_KEYMAP_SLIDERS_NODE, okay) +#define ZMK_KEYMAP_SLIDERS_LEN DT_PROP_LEN(ZMK_KEYMAP_SLIDERS_NODE, sliders) +#define ZMK_KEYMAP_SLIDERS_BY_IDX(idx) DT_PHANDLE_BY_IDX(ZMK_KEYMAP_SLIDERS_NODE, sliders, idx) diff --git a/app/include/zmk/split/bluetooth/service.h b/app/include/zmk/split/bluetooth/service.h index 112cd552942..171d107a64e 100644 --- a/app/include/zmk/split/bluetooth/service.h +++ b/app/include/zmk/split/bluetooth/service.h @@ -6,8 +6,12 @@ #pragma once +<<<<<<< HEAD #include #include +======= +#include +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 #define ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN 9 @@ -30,8 +34,13 @@ struct zmk_split_run_behavior_payload { char behavior_dev[ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN]; } __packed; + int zmk_split_bt_position_pressed(uint8_t position); int zmk_split_bt_position_released(uint8_t position); +<<<<<<< HEAD int zmk_split_bt_sensor_triggered(uint8_t sensor_index, const struct zmk_sensor_channel_data channel_data[], size_t channel_data_size); +======= +int zmk_split_bt_sensor_triggered(uint8_t sensor_number, struct sensor_value value); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 diff --git a/app/include/zmk/split/bluetooth/uuid.h b/app/include/zmk/split/bluetooth/uuid.h index dccdfc804c5..dff9df1e374 100644 --- a/app/include/zmk/split/bluetooth/uuid.h +++ b/app/include/zmk/split/bluetooth/uuid.h @@ -16,5 +16,9 @@ #define ZMK_SPLIT_BT_SERVICE_UUID ZMK_BT_SPLIT_UUID(0x00000000) #define ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID ZMK_BT_SPLIT_UUID(0x00000001) #define ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID ZMK_BT_SPLIT_UUID(0x00000002) +<<<<<<< HEAD #define ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID ZMK_BT_SPLIT_UUID(0x00000003) #define ZMK_SPLIT_BT_UPDATE_HID_INDICATORS_UUID ZMK_BT_SPLIT_UUID(0x00000004) +======= +#define ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID ZMK_BT_SPLIT_UUID(0x00000002) +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 diff --git a/app/include/zmk/trackballs.h b/app/include/zmk/trackballs.h new file mode 100644 index 00000000000..496c226b535 --- /dev/null +++ b/app/include/zmk/trackballs.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#define ZMK_KEYMAP_TRACKBALLS_NODE DT_INST(0, zmk_keymap_trackballs) +#define ZMK_KEYMAP_HAS_TRACKBALLS DT_NODE_HAS_STATUS(ZMK_KEYMAP_TRACKBALLS_NODE, okay) +#define ZMK_KEYMAP_TRACKBALLS_LEN DT_PROP_LEN(ZMK_KEYMAP_TRACKBALLS_NODE, trackballs) +#define ZMK_KEYMAP_TRACKBALLS_BY_IDX(idx) DT_PHANDLE_BY_IDX(ZMK_KEYMAP_TRACKBALLS_NODE, trackballs, idx) diff --git a/app/module/drivers/display/il0323.c b/app/module/drivers/display/il0323.c index c9d72fc529b..212a57de3bc 100644 --- a/app/module/drivers/display/il0323.c +++ b/app/module/drivers/display/il0323.c @@ -24,6 +24,26 @@ LOG_MODULE_REGISTER(il0323, CONFIG_DISPLAY_LOG_LEVEL); * */ +<<<<<<< HEAD:app/module/drivers/display/il0323.c +======= +#define IL0323_SPI_FREQ DT_INST_PROP(0, spi_max_frequency) +#define IL0323_BUS_NAME DT_INST_BUS_LABEL(0) +#define IL0323_DC_PIN DT_INST_GPIO_PIN(0, dc_gpios) +#define IL0323_DC_FLAGS DT_INST_GPIO_FLAGS(0, dc_gpios) +#define IL0323_DC_CNTRL DT_INST_GPIO_LABEL(0, dc_gpios) +#define IL0323_CS_PIN DT_INST_SPI_DEV_CS_GPIOS_PIN(0) +#define IL0323_CS_FLAGS DT_INST_SPI_DEV_CS_GPIOS_FLAGS(0) +#if DT_INST_SPI_DEV_HAS_CS_GPIOS(0) +#define IL0323_CS_CNTRL DT_INST_SPI_DEV_CS_GPIOS_LABEL(0) +#endif +#define IL0323_BUSY_PIN DT_INST_GPIO_PIN(0, busy_gpios) +#define IL0323_BUSY_CNTRL DT_INST_GPIO_LABEL(0, busy_gpios) +#define IL0323_BUSY_FLAGS DT_INST_GPIO_FLAGS(0, busy_gpios) +/* #define IL0323_RESET_PIN DT_INST_GPIO_PIN(0, reset_gpios) */ +/* #define IL0323_RESET_CNTRL DT_INST_GPIO_LABEL(0, reset_gpios) */ +/* #define IL0323_RESET_FLAGS DT_INST_GPIO_FLAGS(0, reset_gpios) */ + +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048:app/drivers/display/il0323.c #define EPD_PANEL_WIDTH DT_INST_PROP(0, width) #define EPD_PANEL_HEIGHT DT_INST_PROP(0, height) #define IL0323_PIXELS_PER_BYTE 8U @@ -269,11 +289,19 @@ static int il0323_controller_init(const struct device *dev) { LOG_DBG(""); +<<<<<<< HEAD:app/module/drivers/display/il0323.c gpio_pin_set_dt(&cfg->reset, 1); k_msleep(IL0323_RESET_DELAY); gpio_pin_set_dt(&cfg->reset, 0); k_msleep(IL0323_RESET_DELAY); il0323_busy_wait(cfg); +======= + /* gpio_pin_set(driver->reset, IL0323_RESET_PIN, 1); */ + /* k_msleep(IL0323_RESET_DELAY); */ + /* gpio_pin_set(driver->reset, IL0323_RESET_PIN, 0); */ + /* k_msleep(IL0323_RESET_DELAY); */ + /* il0323_busy_wait(driver); */ +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048:app/drivers/display/il0323.c LOG_DBG("Initialize IL0323 controller"); @@ -290,7 +318,14 @@ static int il0323_controller_init(const struct device *dev) { il0323_busy_wait(cfg); /* Pannel settings, KW mode */ +#if IS_ENABLED(CONFIG_NRFMACRO_EPD_ROTATE_180) + // rotate the screen upside down by scanning in from right -> left, down -> up + tmp[0] = IL0323_PSR_SHD | IL0323_PSR_RST; +#else + // scanning in from left -> right, up -> down tmp[0] = IL0323_PSR_UD | IL0323_PSR_SHL | IL0323_PSR_SHD | IL0323_PSR_RST; +#endif + #if EPD_PANEL_WIDTH == 80 #if EPD_PANEL_HEIGHT == 128 @@ -347,12 +382,27 @@ static int il0323_init(const struct device *dev) { return -EIO; } +<<<<<<< HEAD:app/module/drivers/display/il0323.c if (!device_is_ready(cfg->reset.port)) { LOG_ERR("Could not get GPIO port for IL0323 reset"); return -EIO; } gpio_pin_configure_dt(&cfg->reset, GPIO_OUTPUT_INACTIVE); +======= + driver->spi_config.frequency = IL0323_SPI_FREQ; + driver->spi_config.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8); + driver->spi_config.slave = DT_INST_REG_ADDR(0); + driver->spi_config.cs = NULL; + + /* driver->reset = device_get_binding(IL0323_RESET_CNTRL); */ + /* if (driver->reset == NULL) { */ + /* LOG_ERR("Could not get GPIO port for IL0323 reset"); */ + /* return -EIO; */ + /* } */ + + /* gpio_pin_configure(driver->reset, IL0323_RESET_PIN, GPIO_OUTPUT_INACTIVE | IL0323_RESET_FLAGS); */ +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048:app/drivers/display/il0323.c if (!device_is_ready(cfg->dc.port)) { LOG_ERR("Could not get GPIO port for IL0323 DC signal"); @@ -391,5 +441,9 @@ static struct display_driver_api il0323_driver_api = { .set_orientation = il0323_set_orientation, }; +<<<<<<< HEAD:app/module/drivers/display/il0323.c DEVICE_DT_INST_DEFINE(0, il0323_init, NULL, NULL, &il0323_config, POST_KERNEL, +======= +DEVICE_DT_INST_DEFINE(0, il0323_init, NULL, &il0323_driver, NULL, POST_KERNEL, +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048:app/drivers/display/il0323.c CONFIG_APPLICATION_INIT_PRIORITY, &il0323_driver_api); diff --git a/app/module/drivers/kscan/CMakeLists.txt b/app/module/drivers/kscan/CMakeLists.txt index 5b05af767e2..5e6916b6734 100644 --- a/app/module/drivers/kscan/CMakeLists.txt +++ b/app/module/drivers/kscan/CMakeLists.txt @@ -3,10 +3,16 @@ zephyr_library_amend() +<<<<<<< HEAD:app/module/drivers/kscan/CMakeLists.txt zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER kscan_gpio.c) +======= +zephyr_library_sources(kscan_wrapper.c) +zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER debounce.c) +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048:app/drivers/kscan/CMakeLists.txt zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_MATRIX kscan_gpio_matrix.c) zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_CHARLIEPLEX kscan_gpio_charlieplex.c) zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DIRECT kscan_gpio_direct.c) zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DEMUX kscan_gpio_demux.c) zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_MOCK_DRIVER kscan_mock.c) zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_COMPOSITE_DRIVER kscan_composite.c) +zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_CAP1203 kscan_cap1203.c) diff --git a/app/module/drivers/kscan/kscan_cap1203.c b/app/module/drivers/kscan/kscan_cap1203.c new file mode 100644 index 00000000000..2969936c834 --- /dev/null +++ b/app/module/drivers/kscan/kscan_cap1203.c @@ -0,0 +1,644 @@ +/* + * Copyright (c) 2022 Yong Zhou + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_kscan_cap1203 + +#define USE_POLLING IS_ENABLED(CONFIG_ZMK_KSCAN_CAP1203_POLL) + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_CAP1203_MIX_MODE) || defined(CONFIG_CAP1203_SLIDER_MODE) +#include +#endif + +LOG_MODULE_REGISTER(kscan_cap1203, CONFIG_ZMK_LOG_LEVEL); + +/* List of important registers and associated commands */ +#define REG_PRODUCT_ID 0xFD +#define PRODUCT_ID 0x6D +#define REG_VENDOR_ID 0xFE +#define VENDOR_ID 0x5D +#define REG_REVISION 0xFF +#define REVISION_ID 0x00 + +#define REG_MAIN_CONTROL 0x0 +#define CONTROL_INT 0x1 + +#define REG_GENERAL_STATUS 0x02 +#define REG_INPUT_STATUS 0x03 + +#define REG_INTERRUPT_ENABLE 0x27 +#define INTERRUPT_ENABLE 0x7 +#define INTERRUPT_DISABLE 0x0 + +#define REG_REPEAT_ENABLE 0x28 +#define REPEAT_ENABLE 0x7 +#define REPEAT_DISABLE 0x0 + +#define REG_MULT_CONFIG 0x2A +#define MULT_BLK_EN_POS 7 +#define B_MULT_T1_POS 3 +#define B_MULT_T0_POS 2 + +#define REG_CONFIGURATION_2 0x44 +#define RELEASE_INT_POS 0 + +/* device driver data */ +struct kscan_cap1203_config { + struct i2c_dt_spec i2c; + struct gpio_dt_spec int_gpio; + bool invert_direction; +}; + +struct kscan_cap1203_data { +#if defined(CONFIG_CAP1203_MIX_MODE) || defined(CONFIG_CAP1203_SLIDER_MODE) + struct slider_data slider_data; +#endif + +#ifdef CONFIG_CAP1203_MIX_MODE + bool is_slide; // slide or button manueover + uint8_t press_state; // accumulated sensor status at end of cycle + int64_t update_duration; +#endif + + const struct device *dev; + kscan_callback_t callback; // zmk's kscan callback + struct k_timer timer; + struct k_work work; // actual processing work + struct gpio_callback int_gpio_cb; // alert gpio pin callback + uint8_t touch_state; // current sensor status + int update_counter; +}; + +#if defined(CONFIG_CAP1203_SLIDER_MODE) || defined(CONFIG_CAP1203_MIX_MODE) +/* array of the status patterns, the array_index+1 is the position indicator */ +/* static uint8_t const slider_pattern[5] = {1, 3, 2, 6, 4}; */ +/* array of slider positions with slider pattern as array index */ +/* The position of unknown slider patterns is defined to be 0 */ +static uint8_t const slider_position[8] = {0, 1, 3, 2, 5, 0, 4, 0}; +#endif + +/* Functions and variables for debugging usage */ +#ifdef CONFIG_ZMK_USB_LOGGING +static inline void print_register(const struct i2c_dt_spec *i2c, uint8_t reg, const char* prefix) +{ + uint8_t status; + int err = i2c_reg_read_byte_dt(i2c, reg, &status); + if (err < 0) { + LOG_ERR("Debug can's read register: 0x%x", reg); + return; + } + LOG_INF("%s: register 0x%x = 0x%x", prefix, reg, status); + return; +} +#endif + +/* Write a single bit in a register without touching other bits */ +static inline int kscan_cap1203_bit_write(const struct i2c_dt_spec *i2c, uint8_t reg, \ + uint8_t pos, bool enable) +{ + uint8_t val; + int err; + + if((err=i2c_reg_read_byte_dt(i2c, reg, &val))) { + return err; + } + + if( enable ) + WRITE_BIT(val, pos, 1); + else + WRITE_BIT(val, pos, 0); + + return i2c_reg_write_byte_dt(i2c, reg, val); +} + +/* Check the status of the sensor by comparing the vid, revision and pid with the datasheet */ +static inline int kscan_cap1203_check_firmware(const struct device *dev) +{ + const struct kscan_cap1203_config *config = dev->config; + + uint8_t val; + int err; + + if((err=i2c_reg_read_byte_dt(&config->i2c, REG_PRODUCT_ID, &val))) { + LOG_INF("Can't read register: product id"); + return err; + } + else if( val != PRODUCT_ID ) { + LOG_INF("Unequal product id 0x%x (expected: 0x%x)", val, PRODUCT_ID); + return -EIO; + } + + if((err=i2c_reg_read_byte_dt(&config->i2c, REG_VENDOR_ID, &val))) { + LOG_INF("Can't read register: vendor id"); + return err; + } + else if( val != VENDOR_ID ) { + LOG_INF("Unequal vendor id 0x%x (expected: 0x%x)", val, VENDOR_ID); + return -EIO; + } + + return 0; +} + +/* Config multiple touch circuitry */ +inline static int kscan_cap1203_configure_multiple_touch(const struct i2c_dt_spec *i2c, \ + bool enable, \ + int num) +{ + uint8_t val=0; + + if(enable) { + WRITE_BIT(val, MULT_BLK_EN_POS, 1); + + switch (num) { + case 1: + WRITE_BIT(val, B_MULT_T1_POS, 0); + WRITE_BIT(val, B_MULT_T0_POS, 0); + break; + case 2: + WRITE_BIT(val, B_MULT_T1_POS, 0); + WRITE_BIT(val, B_MULT_T0_POS, 1); + break; + case 3: + WRITE_BIT(val, B_MULT_T1_POS, 1); + WRITE_BIT(val, B_MULT_T0_POS, 0); + break; + default: + LOG_ERR("Number of channels is out of range: max=3"); + return -EINVAL; + } + } + else { + WRITE_BIT(val, MULT_BLK_EN_POS, 0); + } + + return i2c_reg_write_byte_dt(i2c, REG_MULT_CONFIG, val); +} +/* Enable/disable generation of release interrupt */ +static int kscan_cap1203_enable_release_interrupt(const struct i2c_dt_spec *i2c,\ + bool enable) +{ + return kscan_cap1203_bit_write(i2c, REG_CONFIGURATION_2, RELEASE_INT_POS, !enable); +} + + +/* De-assert alert line and clear the sensor status input register */ +static int kscan_cap1203_clear_interrupt(const struct i2c_dt_spec *i2c) +{ + uint8_t ctrl; + int r; + + r = i2c_reg_read_byte_dt(i2c, REG_MAIN_CONTROL, &ctrl); + if (r < 0) { + return r; + } + + ctrl = ctrl & ~CONTROL_INT; + + return i2c_reg_write_byte_dt(i2c, REG_MAIN_CONTROL, ctrl); +} + +/* Enable/disable the alert line */ +static int kscan_cap1203_enable_interrupt(const struct i2c_dt_spec *i2c, bool enable) +{ + uint8_t intr = enable ? INTERRUPT_ENABLE : INTERRUPT_DISABLE; + + return i2c_reg_write_byte_dt(i2c, REG_INTERRUPT_ENABLE, intr); +} + +/* determine the press status based on latest sensor input */ +// arg1 new_input: the current status input register value +// arg2 ch: the sensor channel to be tested +// arg3 pressed: whether the state change is pressed or released +// return: true if there is state change, otherwise false +inline static bool kscan_cap1203_change_state(uint8_t *old_input, \ + uint8_t *new_input, \ + int ch, \ + bool *pressed) +{ + + if((*old_input & BIT(ch) ) != (*new_input & BIT(ch))) { + *pressed = *new_input & BIT(ch); + return true; + } + return false; +} + +/* read the current touch status */ +static int kscan_cap1203_read(const struct device *dev) +{ + const struct kscan_cap1203_config *config = dev->config; + struct kscan_cap1203_data *data = dev->data; + int r; + uint8_t input; + + LOG_INF("Beginning of ISR:"); +#ifdef CONFIG_CAP1203_BUTTON_MODE + bool pressed; + + // read general status +#ifdef CONFIG_ZMK_USB_LOGGING + print_register(&config->i2c, REG_GENERAL_STATUS, "General Status"); +#endif + + // read sensor input status + r = i2c_reg_read_byte_dt(&config->i2c, REG_INPUT_STATUS, &input); + if (r < 0) { + return r; + } + LOG_INF("Initial input status: 0x%x (old: 0x%x)", input, data->touch_state); + + // check the state change, only pressed event can be discovered at this stage + for( int ch=0; ch < 3; ch++ ) { + if(kscan_cap1203_change_state(&data->touch_state, &input, ch, &pressed)) { + data->callback(dev, 0, ch, pressed); + LOG_INF("Pad %d %s", ch+1, pressed ? "pressed" : "released"); + } + } + + // Clear INT bit to clear SENSOR INPUT STATUS bits and dis-claim interrupt line + r = kscan_cap1203_clear_interrupt(&config->i2c); + if (r < 0) { + return r; + } + + // read sensor input status again, this time to discover release event + r = i2c_reg_read_byte_dt(&config->i2c, REG_INPUT_STATUS, &data->touch_state); + if (r < 0) { + return r; + } + LOG_INF("Input status after clearing: 0x%x (old: 0x%x)", data->touch_state, input); + + // if interrput is triggered by release, there will be state change after claering + for( int ch=0; ch < 3; ch++ ) { + if(kscan_cap1203_change_state(&input, &data->touch_state, ch, &pressed)) { + data->callback(dev, 0, ch, pressed); + LOG_INF("Pad %d %s", ch+1, pressed ? "pressed" : "released"); + } + } + +#else // slider or mix mode + // read general status +#ifdef CONFIG_ZMK_USB_LOGGING + data->update_counter++; + print_register(&config->i2c, REG_GENERAL_STATUS, "General Status"); + if(!data->touch_state) + LOG_INF("Start of one cycle"); +#endif + + struct slider_data *slider_data = dev->data; + // get the curren timestamp + int64_t timestamp = k_uptime_get(); + +#ifdef CONFIG_CAP1203_MIX_MODE + // get cycle start time + if(data->touch_state == 0) { + data->update_duration = k_uptime_get(); + } +#endif + + // First reading of sensor input status, only pressed info updated + r = i2c_reg_read_byte_dt(&config->i2c, REG_INPUT_STATUS, &input); + if (r < 0) { + return r; + } + // Clear INT bit to update release info + r = kscan_cap1203_clear_interrupt(&config->i2c); + if (r < 0) { + return r; + } + // Second reading of sensor input status, which includes release info + r = i2c_reg_read_byte_dt(&config->i2c, REG_INPUT_STATUS, &input); + if (r < 0) { + return r; + } + LOG_INF("Update %d status: 0x%x", data->update_counter, input); + + // Process the slider pattern, unknown patterns are skipped + if(input) { // skip last update + +#ifdef CONFIG_CAP1203_MIX_MODE + data->press_state |= input; +#endif + + if(data->touch_state != 0) { // also skip the first update for slider + slider_data->delta_position = slider_position[input] - slider_data->step; + slider_data->delta_time = timestamp - slider_data->pre_ts; + + if (slider_data->delta_position != 0) { +#ifdef CONFIG_ZMK_USB_LOGGING + slider_data->acc_position += slider_data->delta_position; +#endif + +#ifdef CONFIG_CAP1203_MIX_MODE + if(!data->is_slide) { + data->is_slide = true; + LOG_INF("Discover slide movement!"); + } +#endif + + // slider callback to process the deltas + if (slider_data->callback) + slider_data->callback(dev, config->invert_direction ? -slider_data->delta_position : slider_data->delta_position, + slider_data->delta_time); + } + LOG_INF("dPos: %d, dT: %d ms", slider_data->delta_position, slider_data->delta_time); + } + + } + + // book-keeping stuff + data->touch_state = input; + slider_data->step = slider_position[input]; + slider_data->pre_ts = timestamp; + + if(!input) { // reach the end of slide gesture +#ifdef CONFIG_CAP1203_MIX_MODE + // calculate the cycle duration in ms + data->update_duration = k_uptime_get() - data->update_duration; + + if(data->is_slide) { + LOG_INF("End of one cycle. Slide manuover, total delta: %d", slider_data->acc_position); + data->is_slide = false; + } + else if( data->update_duration <= 200 ) { // send button tap + LOG_INF("End of one cycle. Tap manuover, pressed buttons: %d", data->press_state); + + // send press state + for(int i=0; i < 3; i++) { + if(BIT(i) & data->press_state) { + data->callback(dev, 0, i, true); + } + } + + k_msleep(5); + + // send release state + for(int i=0; i < 3; i++) { + if(BIT(i) & data->press_state) { + data->callback(dev, 0, i, false); + } + } + + data->press_state = 0; + } + else + LOG_INF("End of one cycle. Cancelled slide manueover"); +#else + LOG_INF("End of one cycle. Total delta: %d", slider_data->acc_position); +#endif + + slider_data->step = 0; + slider_data->delta_position = 0; + slider_data->acc_position = 0; + slider_data->delta_time = 0; + data->update_counter = 0; + } +#endif + + LOG_INF("End of ISR.\n"); + return 0; +} + +/* the actual work to process each alert or polling */ +static void kscan_cap1203_work_handler(struct k_work *work) +{ + struct kscan_cap1203_data *data = CONTAINER_OF(work, struct kscan_cap1203_data, work); + + kscan_cap1203_read(data->dev); +} + +/* ISR handler: immediatly dispatch the job to the work handler */ +static void kscan_cap1203_irq_handler(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct kscan_cap1203_data *data = CONTAINER_OF(cb, struct kscan_cap1203_data, int_gpio_cb); + + k_work_submit(&data->work); +} + +/* Timer handler in poll mode: immediately dispatch the job to the actual work handler */ +#if USE_POLLING +static void kscan_cap1203_timer_handler(struct k_timer *timer) +{ + struct kscan_cap1203_data *data = CONTAINER_OF(timer, struct kscan_cap1203_data, timer); + + k_work_submit(&data->work); +} +#endif + +static int kscan_cap1203_configure(const struct device *dev, + kscan_callback_t callback) +{ + struct kscan_cap1203_data *data = dev->data; + const struct kscan_cap1203_config *config = dev->config; + + data->callback = callback; + + if (config->int_gpio.port != NULL) { + int r; + + /* Clear pending interrupt */ + r = kscan_cap1203_clear_interrupt(&config->i2c); + if (r < 0) { + LOG_ERR("Could not clear interrupt"); + return r; + } + + r = kscan_cap1203_enable_interrupt(&config->i2c, true); + if (r < 0) { + LOG_ERR("Could not configure interrupt"); + return r; + } + } + + return 0; +} + +static int kscan_cap1203_enable_callback(const struct device *dev) +{ + struct kscan_cap1203_data *data = dev->data; + + const struct kscan_cap1203_config *config = dev->config; + + if (config->int_gpio.port != NULL) { + LOG_DBG("enable interrupt callback"); + gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); + } +#if USE_POLLING + else { + LOG_DBG("enable timer callback"); + k_timer_start(&data->timer, K_MSEC(CONFIG_ZMK_KSCAN_CAP1203_PERIOD), + K_MSEC(CONFIG_ZMK_KSCAN_CAP1203_PERIOD)); + } +#endif + return 0; +} + +static int kscan_cap1203_disable_callback(const struct device *dev) +{ + struct kscan_cap1203_data *data = dev->data; + + const struct kscan_cap1203_config *config = dev->config; + + if (config->int_gpio.port != NULL) { + LOG_DBG("disable interrupt callback"); + gpio_remove_callback(config->int_gpio.port, &data->int_gpio_cb); + } +#if USE_POLLING + else { + LOG_DBG("disable timer callback"); + k_timer_stop(&data->timer); + } +#endif + return 0; +} + +static int kscan_cap1203_init(const struct device *dev) +{ + const struct kscan_cap1203_config *config = dev->config; + struct kscan_cap1203_data *data = dev->data; + int r; + + // check readiness of i2c bus + if (!device_is_ready(config->i2c.bus)) { + LOG_ERR("I2C controller device not ready"); + return -ENODEV; + } + + // init data structure + data->dev = dev; + + k_work_init(&data->work, kscan_cap1203_work_handler); + + // init alert interrupt pin or poll timer + if (config->int_gpio.port != NULL) { + LOG_DBG("Init interrupt mode"); + if (!device_is_ready(config->int_gpio.port)) { + LOG_ERR("Interrupt GPIO controller device not ready"); + return -ENODEV; + } + + r = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT); + if (r < 0) { + LOG_ERR("Could not confighure interrupt GPIO pin"); + return r; + } + + r = gpio_pin_interrupt_configure_dt(&config->int_gpio, + GPIO_INT_EDGE_TO_ACTIVE); + if (r < 0) { + LOG_ERR("Could not configure interrupt GPIO interrupt"); + return r; + } + + gpio_init_callback(&data->int_gpio_cb, kscan_cap1203_irq_handler, + BIT(config->int_gpio.pin)); + } +#if USE_POLLING + else { + LOG_DBG("Init poll mode"); + k_timer_init(&data->timer, kscan_cap1203_timer_handler, NULL); + + // disable alert function in poll mode + r = kscan_cap1203_enable_interrupt(&config->i2c, false); + if (r < 0) { + LOG_ERR("Could not configure interrupt"); + return r; + } + } +#endif + + // configure release interrupt + r = kscan_cap1203_enable_release_interrupt(&config->i2c, true); + if(r) { + LOG_ERR("Could not configure release interrupt"); + return r; + } + + // configure repeat interrupt + r = i2c_reg_write_byte_dt(&config->i2c, REG_REPEAT_ENABLE, REPEAT_DISABLE); + if (r < 0) { + LOG_ERR("Could not configure repeat-rate interrupt"); + return r; + } + + // configure multi-touch circuitry + r = kscan_cap1203_configure_multiple_touch(&config->i2c, true, 3); + if (r < 0) { + LOG_ERR("Could not configure multi-touch circuitry"); + return r; + } + + // End of init + LOG_INF("Init success"); + + return 0; +} + +#if defined(CONFIG_CAP1203_MIX_MODE) || defined(CONFIG_CAP1203_SLIDER_MODE) +static void kscan_cap1203_slider_configure(const struct device *dev, + kscan_slider_callback_t callback, + int id) +{ + struct slider_data *slider_data = dev->data; + slider_data->callback = callback; + slider_data->id = id; + + kscan_cap1203_enable_callback(dev); +} + +static struct kscan_slider_api kscan_cap1203_slider_api = { + { + .config = kscan_cap1203_configure, + .enable_callback = kscan_cap1203_enable_callback, + .disable_callback = kscan_cap1203_disable_callback, + }, + .slider_config = kscan_cap1203_slider_configure +}; + +#define KSCAN_CAP1203_INIT(index) \ + static const struct kscan_cap1203_config kscan_cap1203_config_##index = { \ + .i2c = I2C_DT_SPEC_INST_GET(index), \ + .int_gpio = GPIO_DT_SPEC_INST_GET_OR(index, int_gpios, {0}), \ + .invert_direction = DT_INST_PROP(index, invert_direction), \ + }; \ + static struct kscan_cap1203_data kscan_cap1203_data_##index; \ + DEVICE_DT_INST_DEFINE(index, kscan_cap1203_init, NULL, \ + &kscan_cap1203_data_##index, &kscan_cap1203_config_##index, \ + APPLICATION, CONFIG_ZMK_KSCAN_INIT_PRIORITY, \ + &(kscan_cap1203_slider_api.kscan_api)); +#else // pure button mode +static const struct kscan_driver_api kscan_cap1203_driver_api = { + .config = kscan_cap1203_configure, + .enable_callback = kscan_cap1203_enable_callback, + .disable_callback = kscan_cap1203_disable_callback, +}; +#define KSCAN_CAP1203_INIT(index) \ + static const struct kscan_cap1203_config kscan_cap1203_config_##index = { \ + .i2c = I2C_DT_SPEC_INST_GET(index), \ + .int_gpio = GPIO_DT_SPEC_INST_GET_OR(index, int_gpios, {0}), \ + }; \ + static struct kscan_cap1203_data kscan_cap1203_data_##index; \ + DEVICE_DT_INST_DEFINE(index, kscan_cap1203_init, NULL, \ + &kscan_cap1203_data_##index, &kscan_cap1203_config_##index, \ + APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY , \ + &kscan_cap1203_driver_api); +#endif + +DT_INST_FOREACH_STATUS_OKAY(KSCAN_CAP1203_INIT) diff --git a/app/module/drivers/kscan/kscan_gpio_direct.c b/app/module/drivers/kscan/kscan_gpio_direct.c index b5e77f63301..436b03c6179 100644 --- a/app/module/drivers/kscan/kscan_gpio_direct.c +++ b/app/module/drivers/kscan/kscan_gpio_direct.c @@ -355,7 +355,11 @@ static const struct kscan_driver_api kscan_direct_api = { }; \ \ DEVICE_DT_INST_DEFINE(n, &kscan_direct_init, NULL, &kscan_direct_data_##n, \ +<<<<<<< HEAD:app/module/drivers/kscan/kscan_gpio_direct.c &kscan_direct_config_##n, POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \ +======= + &kscan_direct_config_##n, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048:app/drivers/kscan/kscan_gpio_direct.c &kscan_direct_api); DT_INST_FOREACH_STATUS_OKAY(KSCAN_DIRECT_INIT); diff --git a/app/module/drivers/kscan/kscan_wrapper.c b/app/module/drivers/kscan/kscan_wrapper.c new file mode 100644 index 00000000000..d15f0c1fc7d --- /dev/null +++ b/app/module/drivers/kscan/kscan_wrapper.c @@ -0,0 +1,16 @@ + +#include + +void kscan_slider_config(const struct device *dev, + kscan_slider_callback_t callback, + int id) +{ + const struct kscan_driver_api *api = + (struct kscan_driver_api *)dev->api; + + struct kscan_slider_api *slider_api = CONTAINER_OF(api, struct kscan_slider_api, kscan_api); + __ASSERT(slider_api ? true : false, "The kscan_slider_api is not used."); + + slider_api->slider_config(dev, callback, id); + return; +}; diff --git a/app/module/drivers/sensor/CMakeLists.txt b/app/module/drivers/sensor/CMakeLists.txt index cd1a1c45066..2c0f5afb3c3 100644 --- a/app/module/drivers/sensor/CMakeLists.txt +++ b/app/module/drivers/sensor/CMakeLists.txt @@ -3,4 +3,14 @@ add_subdirectory_ifdef(CONFIG_ZMK_BATTERY battery) add_subdirectory_ifdef(CONFIG_EC11 ec11) +<<<<<<< HEAD:app/module/drivers/sensor/CMakeLists.txt add_subdirectory_ifdef(CONFIG_ZMK_MAX17048 max17048) +======= +add_subdirectory_ifdef(CONFIG_PMW33XX pmw33xx) +add_subdirectory_ifdef(CONFIG_PINNACLE cirque_trackpad) + +# new impl +add_subdirectory_ifdef(CONFIG_PMW3360 pixart/pmw3360) +add_subdirectory_ifdef(CONFIG_PAW3395 pixart/paw3395) +add_subdirectory_ifdef(CONFIG_PMW3610 pixart/pmw3610) +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048:app/drivers/sensor/CMakeLists.txt diff --git a/app/module/drivers/sensor/Kconfig b/app/module/drivers/sensor/Kconfig index ad570c58c94..456308aaf52 100644 --- a/app/module/drivers/sensor/Kconfig +++ b/app/module/drivers/sensor/Kconfig @@ -5,6 +5,15 @@ if SENSOR rsource "battery/Kconfig" rsource "ec11/Kconfig" +<<<<<<< HEAD:app/module/drivers/sensor/Kconfig rsource "max17048/Kconfig" endif # SENSOR +======= + +rsource "cirque_trackpad/Kconfig" +rsource "pmw33xx/Kconfig" +rsource "pixart/pmw3360/Kconfig" +rsource "pixart/paw3395/Kconfig" +rsource "pixart/pmw3610/Kconfig" +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048:app/drivers/sensor/Kconfig diff --git a/app/module/drivers/sensor/battery/CMakeLists.txt b/app/module/drivers/sensor/battery/CMakeLists.txt index 1203e53a6be..5281981fdea 100644 --- a/app/module/drivers/sensor/battery/CMakeLists.txt +++ b/app/module/drivers/sensor/battery/CMakeLists.txt @@ -7,4 +7,5 @@ zephyr_library() zephyr_library_sources(battery_common.c) zephyr_library_sources_ifdef(CONFIG_ZMK_BATTERY_NRF_VDDH battery_nrf_vddh.c) -zephyr_library_sources_ifdef(CONFIG_ZMK_BATTERY_VOLTAGE_DIVIDER battery_voltage_divider.c) \ No newline at end of file +zephyr_library_sources_ifdef(CONFIG_ZMK_BATTERY_VOLTAGE_DIVIDER battery_voltage_divider.c) +zephyr_library_sources_ifdef(CONFIG_ZMK_BATTERY_MAX17048 battery_max17048.c) diff --git a/app/module/drivers/sensor/battery/battery_max17048.c b/app/module/drivers/sensor/battery/battery_max17048.c new file mode 100644 index 00000000000..c1a03aef030 --- /dev/null +++ b/app/module/drivers/sensor/battery/battery_max17048.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_battery_max17048 + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(max17048, CONFIG_BATTERY_LOG_LEVEL); + +#define REG_VCELL 0x02 // 78.125 uV +#define REG_SOC 0x04 // 1%/256 +#define REG_MODE 0x06 +#define REG_VERSION 0x08 +#define REG_HIBRT 0x0A +#define REG_CONFIG 0x0C +#define REG_VALERT 0x14 +#define REG_CRATE 0x16 // 0.208%/hr +#define REG_VRESET 0x18 // vcell threshold +#define REG_STATUS 0x1A // ov, uv, soc change, soc low, reset alert +#define REG_CMD 0xFE + +struct max17048_config { + struct i2c_dt_spec i2c; + const char *i2c_bus_name; +}; + +struct max17048_data { + const struct device *dev; + uint16_t state_of_charge; + uint16_t vcell; +}; + +static int max17048_read_register(const struct device *dev, uint8_t reg, uint16_t *value) { + const struct max17048_config *config = dev->config; + + uint8_t i2c_data[2]; + int ret = i2c_burst_read_dt(&config->i2c, reg, i2c_data, 2); + if (ret != 0) { + LOG_DBG("Unable to read register"); + return ret; + } + + *value = sys_get_be16(i2c_data); + + return 0; +} + +static int max17048_write_register(const struct device *dev, uint8_t reg, uint16_t value) { + const struct max17048_config *config = dev->config; + + uint8_t buf[2]; + sys_put_be16(value, buf); + + return i2c_burst_write_dt(&config->i2c, reg, buf, 2); +} + +static int max17048_set_rcomp_value(const struct device *dev, uint8_t rcomp_value) { + uint16_t tmp = 0; + int err = max17048_read_register(dev, REG_CONFIG, &tmp); + if (err != 0) { + return err; + } + + tmp = ((uint16_t)rcomp_value << 8) | (tmp & 0xFF); + err = max17048_write_register(dev, REG_CONFIG, tmp); + if (err != 0) { + return err; + } + + LOG_DBG("set RCOMP to %d", rcomp_value); + return 0; +} + +static int max17048_set_sleep_enabled(const struct device *dev, bool sleep) { + uint16_t tmp = 0; + int err = max17048_read_register(dev, REG_CONFIG, &tmp); + if (err != 0) { + return err; + } + + if (sleep) { + tmp |= 0x80; + } else { + tmp &= ~0x0080; + } + + err = max17048_write_register(dev, REG_CONFIG, tmp); + if (err != 0) { + return err; + } + + LOG_DBG("sleep mode %s", sleep ? "enabled" : "disabled"); + return 0; +} + +static int max17048_sample_fetch(const struct device *dev, enum sensor_channel chan) { + struct max17048_data *const data = dev->data; + + if (chan != SENSOR_CHAN_ALL + && chan != SENSOR_CHAN_GAUGE_VOLTAGE + && chan != SENSOR_CHAN_GAUGE_STATE_OF_CHARGE) { + LOG_DBG("unsupported channel %d", chan); + return -ENOTSUP; + } + + int err = max17048_read_register(dev, REG_SOC, &data->state_of_charge); + if (err != 0) { + LOG_WRN("failed to read state-of-charge: %d", err); + return err; + } + + err = max17048_read_register(dev, REG_VCELL, &data->vcell); + if (err != 0) { + LOG_WRN("failed to read vcell: %d", err); + return err; + } + + LOG_INF("read values: soc=%d, vcell=%d", data->state_of_charge, data->vcell); + + return 0; +} + +static int max17048_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) { + struct max17048_data *const data = dev->data; + unsigned int tmp = 0; + + switch (chan) { + case SENSOR_CHAN_GAUGE_VOLTAGE: + // 1250 / 16 = 78.125 + tmp = data->vcell * 1250 / 16; + val->val1 = tmp / 1000000; // in V + val->val2 = tmp % 1000000; // in uV + LOG_INF("Vcell = %d.%d", val->val1, val->val2); + break; + + case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: + val->val1 = (data->state_of_charge >> 8); // in 1% + val->val2 = (data->state_of_charge & 0xFF) * 1000 / 256; // in 0.001% + LOG_INF("SOC = %d.%d%", val->val1, val->val2); + break; + + case SENSOR_CHAN_ALL: + tmp = data->vcell * 1250 / 16; + val->val1 = tmp / 1000000; // in V + val->val2 = tmp % 1000000; // in uV + LOG_INF("Vcell = %d.%d", val->val1, val->val2); + val->val1 = (data->state_of_charge >> 8); // in 1% + val->val2 = (data->state_of_charge & 0xFF) * 1000 / 256; // in 0.001% + LOG_INF("SOC = %d.%d%", val->val1, val->val2); + break; + + default: + return -ENOTSUP; + } + + return 0; +} + +static int max17048_init(const struct device *dev) { + struct max17048_data *data = dev->data; + const struct max17048_config *config = dev->config; + + // check readiness of i2c bus + if (!device_is_ready(config->i2c.bus)) { + LOG_ERR("I2C controller (%s) not ready", config->i2c_bus_name); + return -ENODEV; + } + + // init data structure + data->dev = dev; + + // check version register + uint16_t ic_version = 0; + int err = max17048_read_register(dev, REG_VERSION, &ic_version); + if (err != 0) { + LOG_WRN("could not get IC version!"); + return err; + } + + // bring the device out of sleep + /* max17048_set_sleep_enabled(dev, false); */ + + // set the default rcomp value -- 0x97, as stated in the datasheet + /* max17048_set_rcomp_value(dev, 0x97); */ + + LOG_INF("device initialised at 0x%x (i2c=%s) (version %d)", config->i2c.addr, + config->i2c_bus_name, ic_version); + + return 0; +} + +static const struct sensor_driver_api max17048_api = {.sample_fetch = max17048_sample_fetch, + .channel_get = max17048_channel_get}; + +#define MAX17048_INIT(inst) \ + static struct max17048_config max17048_config_##inst = { \ + .i2c_bus_name = DT_INST_BUS_LABEL(inst), \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + \ + static struct max17048_data max17048_data_##inst = {}; \ + \ + DEVICE_DT_INST_DEFINE(inst, max17048_init, NULL, &max17048_data_##inst, \ + &max17048_config_##inst, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &max17048_api); + +DT_INST_FOREACH_STATUS_OKAY(MAX17048_INIT) diff --git a/app/module/dts/bindings/kscan/zmk,kscan-cap1203.yaml b/app/module/dts/bindings/kscan/zmk,kscan-cap1203.yaml new file mode 100644 index 00000000000..f866f4f4067 --- /dev/null +++ b/app/module/dts/bindings/kscan/zmk,kscan-cap1203.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2022 Yong Zhou +# SPDX-License-Identifier: MIT + +description: CAP1203 3-channel capacitive touch sensor + +compatible: "zmk,kscan-cap1203" + +include: [kscan.yaml, i2c-device.yaml] + +properties: + invert-direction: + type: boolean + int-gpios: + type: phandle-array + required: false diff --git a/app/module/dts/bindings/sensor/cirque,pinnacle.yaml b/app/module/dts/bindings/sensor/cirque,pinnacle.yaml new file mode 100644 index 00000000000..62a8c5ab15f --- /dev/null +++ b/app/module/dts/bindings/sensor/cirque,pinnacle.yaml @@ -0,0 +1,27 @@ +description: | + Sensor driver for the Cirque Pinnacle trackpad ASICs + +compatible: "cirque,pinnacle" + +include: spi-device.yaml + +on-bus: spi + +properties: + spi-max-frequency: + type: int + required: true + description: | + Maximum SPI clock speed supported by the device, in Hz. + dr-gpios: + type: phandle-array + required: true + description: Data ready pin for the trackpad + invert-x: + type: boolean + invert-y: + type: boolean + sleep: + type: boolean + no-taps: + type: boolean diff --git a/app/module/dts/bindings/sensor/pixart,paw3395.yaml b/app/module/dts/bindings/sensor/pixart,paw3395.yaml new file mode 100644 index 00000000000..ad0994a54af --- /dev/null +++ b/app/module/dts/bindings/sensor/pixart,paw3395.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT +description: | + Sensor driver for the pixart PAW3395 optical mouse sensor + +compatible: "pixart,paw3395" + +include: spi-device.yaml + +properties: + label: + type: string + required: true + irq-gpios: + type: phandle-array + required: true + scroll-layer: + type: int + description: the momentary layer used to modifiy move to scroll + required: false diff --git a/app/module/dts/bindings/sensor/pixart,pmw3360.yaml b/app/module/dts/bindings/sensor/pixart,pmw3360.yaml new file mode 100644 index 00000000000..7d86b6dca93 --- /dev/null +++ b/app/module/dts/bindings/sensor/pixart,pmw3360.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT +description: | + Sensor driver for the pixart PMW3360 optical mouse sensor + +compatible: "pixart,pmw3360" + +include: spi-device.yaml + +properties: + label: + type: string + required: true + irq-gpios: + type: phandle-array + required: true + scroll-layer: + type: int + description: the momentary layer used to modifiy move to scroll + required: false diff --git a/app/module/dts/bindings/sensor/pixart,pmw33xx.yaml b/app/module/dts/bindings/sensor/pixart,pmw33xx.yaml new file mode 100644 index 00000000000..7fbe91c89f6 --- /dev/null +++ b/app/module/dts/bindings/sensor/pixart,pmw33xx.yaml @@ -0,0 +1,36 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT +description: | + Sensor driver for the pixart PMW33XX optical mouse sensor supports 3360 built in, and 3389 with external srom +compatible: "pixart,pmw33xx" + +include: spi-device.yaml + +properties: + label: + type: string + required: true + cs-gpios: + type: phandle-array + required: true + description: chip select pin for the sensor + motswk-gpios: + type: phandle-array + required: false + description: interrupt pin for motion + cpi: + type: int + description: mouse cpi + required: false + cpi-dividor: + type: int + description: mouse cpi dividor + required: false + disable-rest: + type: boolean + description: disables mouse rest mode, will decrease battery life + required: false + scroll-layer: + type: int + description: the momentary layer used to modifiy move to scroll + required: false diff --git a/app/module/dts/bindings/sensor/pixart,pmw3610.yml b/app/module/dts/bindings/sensor/pixart,pmw3610.yml new file mode 100644 index 00000000000..eec36383049 --- /dev/null +++ b/app/module/dts/bindings/sensor/pixart,pmw3610.yml @@ -0,0 +1,16 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT +description: | + Sensor driver for the pixart PMW3610 optical mouse sensor + +compatible: "pixart,pmw3610" + +include: spi-device.yaml + +properties: + label: + type: string + required: true + irq-gpios: + type: phandle-array + required: true diff --git a/app/module/dts/bindings/sensor/zmk,battery-max17048.yaml b/app/module/dts/bindings/sensor/zmk,battery-max17048.yaml new file mode 100644 index 00000000000..43c10299bb1 --- /dev/null +++ b/app/module/dts/bindings/sensor/zmk,battery-max17048.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 Yong Zhou +# SPDX-License-Identifier: MIT + +description: Maxim MAX17048 Fuel Gauge + +compatible: "zmk,battery-max17048" + +include: [i2c-device.yaml] diff --git a/app/src/battery.c b/app/src/battery.c index 1295f822486..db85b96e7f1 100644 --- a/app/src/battery.c +++ b/app/src/battery.c @@ -13,7 +13,7 @@ #include -LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); +LOG_MODULE_REGISTER(battery, CONFIG_BATTERY_LOG_LEVEL); #include #include @@ -37,24 +37,36 @@ static const struct device *battery; static int zmk_battery_update(const struct device *battery) { struct sensor_value state_of_charge; + LOG_INF("update soc"); + int rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE); if (rc != 0) { LOG_DBG("Failed to fetch battery values: %d", rc); return rc; } - +#ifdef CONFIG_ZMK_USB_LOGGING + rc = sensor_channel_get(battery, SENSOR_CHAN_ALL, &state_of_charge); +#else rc = sensor_channel_get(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE, &state_of_charge); +#endif if (rc != 0) { LOG_DBG("Failed to get battery state of charge: %d", rc); return rc; } + else + LOG_INF("Latest battery values: %d", state_of_charge.val1); if (last_state_of_charge != state_of_charge.val1) { last_state_of_charge = state_of_charge.val1; +<<<<<<< HEAD #if IS_ENABLED(CONFIG_BT_BAS) LOG_DBG("Setting BAS GATT battery level to %d.", last_state_of_charge); +======= + + LOG_INF("Setting BAS GATT battery level to %d.", last_state_of_charge); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 rc = bt_bas_set_battery_level(last_state_of_charge); @@ -81,7 +93,12 @@ static void zmk_battery_work(struct k_work *work) { K_WORK_DEFINE(battery_work, zmk_battery_work); static void zmk_battery_timer(struct k_timer *timer) { +<<<<<<< HEAD k_work_submit_to_queue(zmk_workqueue_lowprio_work_q(), &battery_work); +======= + LOG_INF("battery timer trigger"); + k_work_submit(&battery_work); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } K_TIMER_DEFINE(battery_timer, zmk_battery_timer, NULL); @@ -108,7 +125,22 @@ static int zmk_battery_init(void) { return -ENODEV; } +<<<<<<< HEAD zmk_battery_start_reporting(); +======= + int rc = zmk_battery_update(battery); + + if (rc != 0) { + LOG_DBG("Failed to update battery value: %d.", rc); + return rc; + } + + /* k_timer_start(&battery_timer, K_MINUTES(1), K_SECONDS(CONFIG_ZMK_BATTERY_REPORT_INTERVAL)); */ + k_timer_start(&battery_timer, K_SECONDS(10), K_SECONDS(CONFIG_ZMK_BATTERY_REPORT_INTERVAL)); + + LOG_INF("battery thread initiated"); + +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 return 0; } diff --git a/app/src/behaviors/behavior_mod_morph.c b/app/src/behaviors/behavior_mod_morph.c index 3a8bf08c198..fd0ed1de5ac 100644 --- a/app/src/behaviors/behavior_mod_morph.c +++ b/app/src/behaviors/behavior_mod_morph.c @@ -46,6 +46,10 @@ static int on_mod_morph_binding_pressed(struct zmk_behavior_binding *binding, } if (zmk_hid_get_explicit_mods() & cfg->mods) { +<<<<<<< HEAD +======= + /* zmk_mod_flags_t trigger_mods = zmk_hid_get_explicit_mods() & cfg->mods; */ +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 zmk_hid_masked_modifiers_set(cfg->masked_mods); data->pressed_binding = (struct zmk_behavior_binding *)&cfg->morph_binding; } else { @@ -66,10 +70,15 @@ static int on_mod_morph_binding_released(struct zmk_behavior_binding *binding, struct zmk_behavior_binding *pressed_binding = data->pressed_binding; data->pressed_binding = NULL; +<<<<<<< HEAD int err; err = behavior_keymap_binding_released(pressed_binding, event); zmk_hid_masked_modifiers_clear(); return err; +======= + zmk_hid_masked_modifiers_clear(); + return behavior_keymap_binding_released(pressed_binding, event); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } static const struct behavior_driver_api behavior_mod_morph_driver_api = { @@ -93,8 +102,13 @@ static int behavior_mod_morph_init(const struct device *dev) { return 0; } .normal_binding = _TRANSFORM_ENTRY(0, n), \ .morph_binding = _TRANSFORM_ENTRY(1, n), \ .mods = DT_INST_PROP(n, mods), \ +<<<<<<< HEAD .masked_mods = COND_CODE_0(DT_INST_NODE_HAS_PROP(n, keep_mods), (DT_INST_PROP(n, mods)), \ (DT_INST_PROP(n, mods) & ~DT_INST_PROP(n, keep_mods))), \ +======= + .masked_mods = COND_CODE_0(DT_INST_NODE_HAS_PROP(n, masked_mods), (0), \ + (DT_INST_PROP(n, masked_mods))), \ +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 }; \ static struct behavior_mod_morph_data behavior_mod_morph_data_##n = {}; \ BEHAVIOR_DT_INST_DEFINE(n, behavior_mod_morph_init, NULL, &behavior_mod_morph_data_##n, \ diff --git a/app/src/behaviors/behavior_momentary_layer.c b/app/src/behaviors/behavior_momentary_layer.c index 0c86e605b55..b868f951b5a 100644 --- a/app/src/behaviors/behavior_momentary_layer.c +++ b/app/src/behaviors/behavior_momentary_layer.c @@ -23,13 +23,22 @@ static int behavior_mo_init(const struct device *dev) { return 0; }; static int mo_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { LOG_DBG("position %d layer %d", event.position, binding->param1); + +#if IS_ENABLED(CONFIG_MYCHANGE_DISPLAY_UPDATE_MO_BEHAVIOR) return zmk_keymap_layer_activate(binding->param1); +#else + return zmk_keymap_layer_activate_noevent(binding->param1); +#endif } static int mo_keymap_binding_released(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { LOG_DBG("position %d layer %d", event.position, binding->param1); +#if IS_ENABLED(CONFIG_MYCHANGE_DISPLAY_UPDATE_MO_BEHAVIOR) return zmk_keymap_layer_deactivate(binding->param1); +#else + return zmk_keymap_layer_deactivate_noevent(binding->param1); +#endif } static const struct behavior_driver_api behavior_mo_driver_api = { diff --git a/app/src/behaviors/behavior_mouse_key_press.c b/app/src/behaviors/behavior_mouse_key_press.c index 9064a1aa5c8..b99ec597e2d 100644 --- a/app/src/behaviors/behavior_mouse_key_press.c +++ b/app/src/behaviors/behavior_mouse_key_press.c @@ -6,9 +6,15 @@ #define DT_DRV_COMPAT zmk_behavior_mouse_key_press +<<<<<<< HEAD #include #include #include +======= +#include +#include +#include +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 #include #include @@ -24,20 +30,31 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); +<<<<<<< HEAD return raise_zmk_mouse_button_state_changed_from_encoded(binding->param1, true, event.timestamp); +======= + return ZMK_EVENT_RAISE( + zmk_mouse_button_state_changed_from_encoded(binding->param1, true, event.timestamp)); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } static int on_keymap_binding_released(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); +<<<<<<< HEAD return raise_zmk_mouse_button_state_changed_from_encoded(binding->param1, false, event.timestamp); +======= + return ZMK_EVENT_RAISE( + zmk_mouse_button_state_changed_from_encoded(binding->param1, false, event.timestamp)); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } static const struct behavior_driver_api behavior_mouse_key_press_driver_api = { .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; +<<<<<<< HEAD #define MKP_INST(n) \ BEHAVIOR_DT_INST_DEFINE(n, behavior_mouse_key_press_init, NULL, NULL, NULL, POST_KERNEL, \ CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ @@ -46,3 +63,13 @@ static const struct behavior_driver_api behavior_mouse_key_press_driver_api = { DT_INST_FOREACH_STATUS_OKAY(MKP_INST) #endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ +======= +#define KP_INST(n) \ + DEVICE_DT_INST_DEFINE(n, behavior_mouse_key_press_init, NULL, NULL, NULL, \ + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_mouse_key_press_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 diff --git a/app/src/behaviors/behavior_mouse_move.c b/app/src/behaviors/behavior_mouse_move.c new file mode 100644 index 00000000000..12552d54892 --- /dev/null +++ b/app/src/behaviors/behavior_mouse_move.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_mouse_move + +#include +#include +#include + +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static int behavior_mouse_move_init(const struct device *dev) { return 0; }; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct mouse_config *config = dev->config; + return ZMK_EVENT_RAISE( + zmk_mouse_move_state_changed_from_encoded(binding->param1, *config, true, event.timestamp)); +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct mouse_config *config = dev->config; + return ZMK_EVENT_RAISE(zmk_mouse_move_state_changed_from_encoded(binding->param1, *config, + false, event.timestamp)); +} + +static const struct behavior_driver_api behavior_mouse_move_driver_api = { + .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; + +#define KP_INST(n) \ + static struct mouse_config behavior_mouse_move_config_##n = { \ + .delay_ms = DT_INST_PROP(n, delay_ms), \ + .time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \ + .acceleration_exponent = DT_INST_PROP(n, acceleration_exponent), \ + }; \ + DEVICE_DT_INST_DEFINE(n, behavior_mouse_move_init, NULL, NULL, \ + &behavior_mouse_move_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_move_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_mouse_scroll.c b/app/src/behaviors/behavior_mouse_scroll.c new file mode 100644 index 00000000000..b6c4b1d31fd --- /dev/null +++ b/app/src/behaviors/behavior_mouse_scroll.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_mouse_scroll + +#include +#include +#include + +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static int behavior_mouse_scroll_init(const struct device *dev) { return 0; }; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct mouse_config *config = dev->config; + return ZMK_EVENT_RAISE(zmk_mouse_scroll_state_changed_from_encoded(binding->param1, *config, + true, event.timestamp)); +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct mouse_config *config = dev->config; + return ZMK_EVENT_RAISE(zmk_mouse_scroll_state_changed_from_encoded(binding->param1, *config, + false, event.timestamp)); +} + +static const struct behavior_driver_api behavior_mouse_scroll_driver_api = { + .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; + +#define KP_INST(n) \ + static struct mouse_config behavior_mouse_scroll_config_##n = { \ + .delay_ms = DT_INST_PROP(n, delay_ms), \ + .time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \ + .acceleration_exponent = DT_INST_PROP(n, acceleration_exponent), \ + }; \ + DEVICE_DT_INST_DEFINE(n, behavior_mouse_scroll_init, NULL, NULL, \ + &behavior_mouse_scroll_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_scroll_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_point_device_directional.c b/app/src/behaviors/behavior_point_device_directional.c new file mode 100644 index 00000000000..4354214bf83 --- /dev/null +++ b/app/src/behaviors/behavior_point_device_directional.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_point_device_directional + +#include +#include +#include +#include + +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +enum pd_dir_mode { + TIME_MODE, + DISTANCE_MODE, + EAGER_MODE +}; + +enum pd_dir_flavor { ONE_DIM, TWO_DIM }; + +struct behavior_point_device_directional_config { + enum pd_dir_mode mode; + enum pd_dir_flavor flavor; + int step_size; +}; + +struct behavior_point_device_directional_data { + int64_t previous_t; + int16_t dt; + int16_t dx; + int16_t dy; +}; + +enum pd_dir_type { X_PLUS = 1, X_MINUS, Y_PLUS, Y_MINUS }; + +static int behavior_point_device_directional_init(const struct device *dev) { return 0; }; + +static inline void pd_dir_reset_distance(const struct behavior_point_device_directional_config *cfg, + struct behavior_point_device_directional_data *data) +{ + if ( data->dx > cfg->step_size ) + data->dx -= cfg->step_size; + else + data->dx = 0; + + if ( data->dy > cfg->step_size ) + data->dy -= cfg->step_size; + else + data->dy = 0; +} + +static inline void pd_dir_reset(const struct behavior_point_device_directional_config *cfg, + struct behavior_point_device_directional_data *data) +{ + switch (cfg->mode) { + case EAGER_MODE: + data->dt = 0; + case TIME_MODE: + data->dx = 0; + data->dy = 0; + data->dt = 0; + break; + case DISTANCE_MODE: + pd_dir_reset_distance(cfg, data); + break; + } + +} + +static inline int pd_dir_time_mode(const struct behavior_point_device_directional_config *cfg, + struct behavior_point_device_directional_data *data, + int16_t dx, int16_t dy, int dt) +{ + // 1. accumulate + data->dx += dx; + data->dy += dy; + data->dt += dt; + + // 2. determine the direction + if( data->dt >= cfg->step_size ) { + switch( cfg->flavor ) { + case ONE_DIM: + return data->dx > 0 ? X_PLUS : X_MINUS; + break; + case TWO_DIM: + if( abs(data->dx) >= abs(data->dy) ) + return data->dx > 0 ? X_PLUS : X_MINUS; + else + return data->dy > 0 ? Y_PLUS : Y_MINUS; + break; + default: + LOG_ERR("unsupported flavor %d", cfg->flavor); + return -ENOTSUP; + } + } + + // 3. direction can't be determied in this event + return 0; +} + +static inline int pd_dir_distance_mode(const struct behavior_point_device_directional_config *cfg, + struct behavior_point_device_directional_data *data, + int16_t dx, int16_t dy) +{ + // 1. accumulate + data->dx += dx; + data->dy += dy; + + // 2. determine the direction + switch (cfg->flavor) { + case ONE_DIM: + { + if( abs(data->dx) >= cfg->step_size ) + return data->dx > 0 ? X_PLUS : X_MINUS; + } + break; + case TWO_DIM: + { + if( abs(data->dx) >= cfg->step_size + && abs(data->dx) >= abs(data->dy) ) + return data->dx > 0 ? X_PLUS : X_MINUS; + else if ( abs(data->dy) >= cfg->step_size + && abs(data->dy) >= abs(data->dx) ) + return data->dy > 0 ? Y_PLUS : Y_MINUS; + } + break; + default: + LOG_ERR("unsupported flavor %d", cfg->flavor); + return -ENOTSUP; + } + + // 3. direction can't be determied in this event + return 0; +} + +static inline int pd_dir_eager_mode(const struct behavior_point_device_directional_config *cfg, + struct behavior_point_device_directional_data *data, + int16_t dx, int16_t dy, int dt) +{ + if ( cfg->flavor != ONE_DIM ) + return -ENOTSUP; + + data->dt += dt; + if( data->dx == 0 + || (data->dx ^ dx) < 0 + || data->dt > cfg->step_size ) { + data->dx = dx; + return dx > 0 ? X_PLUS : X_MINUS; + } + + return 0; +} + +static int on_pd_binding_triggered(struct zmk_behavior_binding *binding, + int16_t dx, int16_t dy, int dt, int64_t timestamp) +{ + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct behavior_point_device_directional_config *cfg = dev->config; + struct behavior_point_device_directional_data *data = dev->data; + + // event arriving outside of the time window is considered a new manueover + if( (timestamp - data->previous_t) > CONFIG_ZMK_BHV_PD_DIR_TIME_WINDOW ) { + data->dx = 0; + data->dy = 0; + data->dt = 0; + } + + // check the direction of the manueover + int index; + switch (cfg->mode) { + case TIME_MODE: + index = pd_dir_time_mode(cfg, data, dx, dy, dt); + break; + case DISTANCE_MODE: + index = pd_dir_distance_mode(cfg, data, dx, dy); + break; + case EAGER_MODE: + index = pd_dir_eager_mode(cfg, data, dx, dy, dt); + break; + default: + LOG_ERR("unsupported work mode %d", cfg->mode); + return -ENOTSUP; + } + + uint32_t keycode; + switch (index) { + case X_PLUS: + keycode = binding->param1; + break; + case X_MINUS: + keycode = binding->param2; + break; + case Y_PLUS: + keycode = binding->param3; + break; + case Y_MINUS: + keycode = binding->param4; + break; + case 0: // undetermied state, wait for next event directly + data->previous_t = timestamp; + return 0; + default: + return -ENOTSUP; + } + + // keycode determined, send press and release + LOG_DBG("SEND keycode: %d", keycode); + ZMK_EVENT_RAISE(zmk_keycode_state_changed_from_encoded(keycode, true, timestamp)); + + k_msleep(5); + + ZMK_EVENT_RAISE(zmk_keycode_state_changed_from_encoded(keycode, false, timestamp)); + + // reset state after sending + data->previous_t = timestamp; + pd_dir_reset(cfg, data); + + return 0; +} + +// +static const struct behavior_driver_api behavior_point_device_directional_driver_api = { + .pd_binding_triggered = on_pd_binding_triggered +}; + +#define KP_INST(n) \ + static struct behavior_point_device_directional_data behavior_pd_dir_data_##n; \ + static struct behavior_point_device_directional_config behavior_pd_dir_config_##n = { \ + .mode = DT_ENUM_IDX(DT_DRV_INST(n), mode), \ + .flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \ + .step_size = DT_INST_PROP(n, step_size), \ + }; \ + DEVICE_DT_INST_DEFINE(n, behavior_point_device_directional_init, NULL, &behavior_pd_dir_data_##n, \ + &behavior_pd_dir_config_##n, \ + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_point_device_directional_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_point_device_incremental.c b/app/src/behaviors/behavior_point_device_incremental.c new file mode 100644 index 00000000000..6ed0e424721 --- /dev/null +++ b/app/src/behaviors/behavior_point_device_incremental.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_point_device_incremental + +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +enum pd_incr_mode { + MOVE_MODE, + SCROLL_MODE +}; + +enum pd_incr_flavor { DEFAULT, SWAP, X_ONLY, Y_ONLY }; + +enum pd_scale_mode { MULTIPLIER, DIVIDOR }; + +struct behavior_point_device_incremental_config { + enum pd_incr_mode mode; + enum pd_incr_flavor flavor; + enum pd_scale_mode scale_mode; + int scale_factor; + bool smoothing; // todo +}; + +static int behavior_point_device_incremental_init(const struct device *dev) { return 0; }; + +static int on_pd_binding_triggered(struct zmk_behavior_binding *binding, + int16_t dx, int16_t dy, int dt, int64_t timestamp) +{ + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct behavior_point_device_incremental_config *cfg = dev->config; + + // set the real dx, dy + int16_t x, y; + switch (cfg->flavor) { + case SWAP: + x = dy; + y = dx; + break; + case X_ONLY: + x = dx; + y = 0; + break; + case Y_ONLY: + x = 0; + y = dy; + break; + default: + x = dx; + y = dy; + break; + } + + // + switch (cfg->scale_mode) { + case MULTIPLIER: + x = x * cfg->scale_factor; + y = y * cfg->scale_factor; + break; + case DIVIDOR: + x = x / cfg->scale_factor; + y = y / cfg->scale_factor; + break; + default: + LOG_ERR("unsupported scale mode %d", cfg->scale_mode); + return -ENOTSUP; + } + + // choose the report type + switch (cfg->mode) { + case MOVE_MODE: + return ZMK_EVENT_RAISE(new_zmk_pd_position_state_changed( + (struct zmk_pd_position_state_changed){.x=x, .y=y})); + case SCROLL_MODE: + return ZMK_EVENT_RAISE(new_zmk_pd_scroll_state_changed( + (struct zmk_pd_scroll_state_changed){.x=x, .y=y})); + default: + LOG_ERR("unsupported work mode %d", cfg->mode); + return -ENOTSUP; + } + + return 0; +} + +static const struct behavior_driver_api behavior_point_device_incremental_driver_api = { + .pd_binding_triggered = on_pd_binding_triggered +}; + +#define KP_INST(n) \ + static struct behavior_point_device_incremental_config behavior_pd_incr_config_##n = { \ + .mode = DT_ENUM_IDX(DT_DRV_INST(n), mode), \ + .flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \ + .scale_mode = DT_ENUM_IDX(DT_DRV_INST(n), scale_mode), \ + .scale_factor = DT_INST_PROP(n, scale_factor), \ + .smoothing = DT_INST_PROP(n, smoothing), \ + }; \ + DEVICE_DT_INST_DEFINE(n, behavior_point_device_incremental_init, NULL, NULL, &behavior_pd_incr_config_##n, \ + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_point_device_incremental_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/ble.c b/app/src/ble.c index 9d81af59298..234a41348e4 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -502,6 +502,9 @@ static void connected(struct bt_conn *conn, uint8_t err) { update_advertising(); + /* LOG_DBG("New connection params: Interval: %d, Latency: %d, RX: %d, TX: %d", info.le.interval, */ + /* info.le.latency, info.le.phy->rx_phy, info.le.phy->tx_phy); */ + if (is_conn_active_profile(conn)) { LOG_DBG("Active profile connected"); k_work_submit(&raise_profile_changed_event_work); @@ -551,7 +554,11 @@ static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t l bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); +<<<<<<< HEAD LOG_DBG("%s: interval %d latency %d timeout %d", addr, interval, latency, timeout); +======= + LOG_INF("%s: interval %d latency %d timeout %d", log_strdup(addr), interval, latency, timeout); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } static struct bt_conn_cb conn_callbacks = { diff --git a/app/src/display/Kconfig b/app/src/display/Kconfig index 356b4760c1b..e19dcdfc5f8 100644 --- a/app/src/display/Kconfig +++ b/app/src/display/Kconfig @@ -87,6 +87,7 @@ config LV_FONT_MONTSERRAT_12 endif # ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN +<<<<<<< HEAD choice ZMK_LV_FONT_DEFAULT_SMALL prompt "Select theme default small font" default ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_12 @@ -172,6 +173,21 @@ choice ZMK_LV_FONT_DEFAULT_SMALL bool "UNSCII 16 (Perfect monospace font)" select LV_FONT_UNSCII_16 endchoice +======= +config ZMK_DISPLAY_FULL_REFRESH_PERIOD + int "(Optional) Period to issue a full refresh to the display (in seconds)" + default 0 + help + Period in seconds for how often to completely refresh/redraw the whole screen. + Most useful for e-ink/EPD displays that require occasional full redraws. + +config MYCHANGE_DISPLAY_UPDATE_MO_BEHAVIOR + bool "(Opional) flag controlling whether the temporary layer change should be updated on the layer status widget" + default y + depends on ZMK_DISPLAY + help + This is useful for EPD display due to the slow fresh rate +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 rsource "widgets/Kconfig" diff --git a/app/src/display/main.c b/app/src/display/main.c index e15e2de0c9a..831a9bf81a7 100644 --- a/app/src/display/main.c +++ b/app/src/display/main.c @@ -50,7 +50,29 @@ struct k_work_q *zmk_display_work_q() { #endif } +<<<<<<< HEAD void display_timer_cb() { k_work_submit_to_queue(zmk_display_work_q(), &display_tick_work); } +======= +#if CONFIG_ZMK_DISPLAY_FULL_REFRESH_PERIOD > 0 +void full_refresh_work_cb(struct k_work *work) { lv_obj_invalidate(lv_scr_act()); } + +K_WORK_DEFINE(full_refresh_work, full_refresh_work_cb); + +void full_refresh_timer_cb() { k_work_submit_to_queue(zmk_display_work_q(), &full_refresh_work); } + +K_TIMER_DEFINE(full_refresh_timer, full_refresh_timer_cb, NULL); + +#endif + +void display_timer_cb() { + lv_tick_inc(TICK_MS); + k_work_submit_to_queue(zmk_display_work_q(), &display_tick_work); +} + +void blank_display_cb(struct k_work *work) { display_blanking_on(display); } + +void unblank_display_cb(struct k_work *work) { display_blanking_off(display); } +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 K_TIMER_DEFINE(display_timer, display_timer_cb, NULL); @@ -74,6 +96,15 @@ static void start_display_updates() { } k_work_submit_to_queue(zmk_display_work_q(), &unblank_display_work); +<<<<<<< HEAD +======= + + k_timer_start(&display_timer, K_MSEC(TICK_MS), K_MSEC(TICK_MS)); +#if CONFIG_ZMK_DISPLAY_FULL_REFRESH_PERIOD > 0 + k_timer_start(&full_refresh_timer, K_SECONDS(CONFIG_ZMK_DISPLAY_FULL_REFRESH_PERIOD), + K_SECONDS(CONFIG_ZMK_DISPLAY_FULL_REFRESH_PERIOD)); +#endif +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } static void stop_display_updates() { @@ -82,6 +113,14 @@ static void stop_display_updates() { } k_work_submit_to_queue(zmk_display_work_q(), &blank_display_work); +<<<<<<< HEAD +======= + + k_timer_stop(&display_timer); +#if CONFIG_ZMK_DISPLAY_FULL_REFRESH_PERIOD > 0 + k_timer_stop(&full_refresh_timer); +#endif +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } #endif diff --git a/app/src/endpoints.c b/app/src/endpoints.c index e583d78a969..16ef3c4a4e5 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -126,7 +126,7 @@ static int send_keyboard_report(void) { case ZMK_TRANSPORT_USB: { int err = zmk_usb_hid_send_keyboard_report(); if (err) { - LOG_ERR("FAILED TO SEND OVER USB: %d", err); + LOG_ERR("FAILED TO SEND OVER USB DUE TO KEYBOARD_REPORT: %d ", err); } return err; } @@ -154,7 +154,7 @@ static int send_consumer_report(void) { case ZMK_TRANSPORT_USB: { int err = zmk_usb_hid_send_consumer_report(); if (err) { - LOG_ERR("FAILED TO SEND OVER USB: %d", err); + LOG_ERR("FAILED TO SEND OVER USB DUE TO CONSUMER: %d ", err); } return err; } @@ -191,6 +191,7 @@ int zmk_endpoints_send_report(uint16_t usage_page) { return -ENOTSUP; } +<<<<<<< HEAD #if IS_ENABLED(CONFIG_ZMK_MOUSE) int zmk_endpoints_send_mouse_report() { switch (current_instance.transport) { @@ -199,27 +200,56 @@ int zmk_endpoints_send_mouse_report() { int err = zmk_usb_hid_send_mouse_report(); if (err) { LOG_ERR("FAILED TO SEND OVER USB: %d", err); +======= +int zmk_endpoints_send_mouse_report() { + struct zmk_hid_mouse_report *mouse_report = zmk_hid_get_mouse_report(); + + switch (current_endpoint) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ZMK_ENDPOINT_USB: { + int err = zmk_usb_hid_send_report((uint8_t *)mouse_report, sizeof(*mouse_report)); + if (err) { + LOG_ERR("FAILED TO SEND OVER USB DUE TO MOUSE: %d ", err); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } return err; } #endif /* IS_ENABLED(CONFIG_ZMK_USB) */ #if IS_ENABLED(CONFIG_ZMK_BLE) +<<<<<<< HEAD case ZMK_TRANSPORT_BLE: { struct zmk_hid_mouse_report *mouse_report = zmk_hid_get_mouse_report(); int err = zmk_hog_send_mouse_report(&mouse_report->body); +======= + case ZMK_ENDPOINT_BLE: { +#if defined(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) || defined(CONFIG_ZMK_PD_SEND_THREAD_DEDICATED) + int err = zmk_hog_send_mouse_report_direct(&mouse_report->body); +#else + int err = zmk_hog_send_mouse_report(&mouse_report->body); +#endif +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 if (err) { LOG_ERR("FAILED TO SEND OVER HOG: %d", err); } return err; } #endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ +<<<<<<< HEAD } LOG_ERR("Unsupported endpoint transport %d", current_instance.transport); return -ENOTSUP; } #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) +======= + + default: + LOG_ERR("Unsupported endpoint %d", current_endpoint); + return -ENOTSUP; + } +} +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 #if IS_ENABLED(CONFIG_SETTINGS) @@ -329,9 +359,13 @@ static int zmk_endpoints_init(void) { static void disconnect_current_endpoint(void) { zmk_hid_keyboard_clear(); zmk_hid_consumer_clear(); +<<<<<<< HEAD #if IS_ENABLED(CONFIG_ZMK_MOUSE) zmk_hid_mouse_clear(); #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) +======= + zmk_hid_mouse_clear(); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 zmk_endpoints_send_report(HID_USAGE_KEY); zmk_endpoints_send_report(HID_USAGE_CONSUMER); diff --git a/app/src/events/mouse_button_state_changed.c b/app/src/events/mouse_button_state_changed.c index 419a7ce956d..8297d315c0e 100644 --- a/app/src/events/mouse_button_state_changed.c +++ b/app/src/events/mouse_button_state_changed.c @@ -4,6 +4,10 @@ * SPDX-License-Identifier: MIT */ +<<<<<<< HEAD +======= +#include +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 #include ZMK_EVENT_IMPL(zmk_mouse_button_state_changed); diff --git a/app/src/events/mouse_move_state_changed.c b/app/src/events/mouse_move_state_changed.c new file mode 100644 index 00000000000..faf89cb8abc --- /dev/null +++ b/app/src/events/mouse_move_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_mouse_move_state_changed); diff --git a/app/src/events/mouse_scroll_state_changed.c b/app/src/events/mouse_scroll_state_changed.c new file mode 100644 index 00000000000..4b4170fe005 --- /dev/null +++ b/app/src/events/mouse_scroll_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_mouse_scroll_state_changed); diff --git a/app/src/events/mouse_tick.c b/app/src/events/mouse_tick.c new file mode 100644 index 00000000000..0930b9fb902 --- /dev/null +++ b/app/src/events/mouse_tick.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_mouse_tick); diff --git a/app/src/events/pd_position_state_changed.c b/app/src/events/pd_position_state_changed.c new file mode 100644 index 00000000000..71e323ddb83 --- /dev/null +++ b/app/src/events/pd_position_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_pd_position_state_changed); diff --git a/app/src/events/pd_raw_event.c b/app/src/events/pd_raw_event.c new file mode 100644 index 00000000000..6626f850c8c --- /dev/null +++ b/app/src/events/pd_raw_event.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_pd_raw_event); diff --git a/app/src/events/pd_scroll_state_changed.c b/app/src/events/pd_scroll_state_changed.c new file mode 100644 index 00000000000..a2b6b077d68 --- /dev/null +++ b/app/src/events/pd_scroll_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_pd_scroll_state_changed); diff --git a/app/src/hid.c b/app/src/hid.c index 8b0c23f37ed..4edd7ba7d89 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -32,6 +32,9 @@ static struct zmk_hid_mouse_report mouse_report = {.report_id = ZMK_HID_REPORT_I #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) +static struct zmk_hid_mouse_report mouse_report = { + .report_id = 4, .body = {.buttons = 0, .x = 0, .y = 0, .scroll_x = 0, .scroll_y = 0}}; + // Keep track of how often a modifier was pressed. // Only release the modifier if the count is 0. static int explicit_modifier_counts[8] = {0, 0, 0, 0, 0, 0, 0, 0}; @@ -41,7 +44,11 @@ static zmk_mod_flags_t masked_modifiers = 0; #define SET_MODIFIERS(mods) \ { \ +<<<<<<< HEAD keyboard_report.body.modifiers = (mods & ~masked_modifiers) | implicit_modifiers; \ +======= + keyboard_report.body.modifiers = (mods | implicit_modifiers) & ~masked_modifiers; \ +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 LOG_DBG("Modifiers set to 0x%02X", keyboard_report.body.modifiers); \ } @@ -268,7 +275,11 @@ int zmk_hid_implicit_modifiers_press(zmk_mod_flags_t new_implicit_modifiers) { return current == GET_MODIFIERS ? 0 : 1; } +<<<<<<< HEAD int zmk_hid_implicit_modifiers_release(void) { +======= +int zmk_hid_implicit_modifiers_release() { +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 implicit_modifiers = 0; zmk_mod_flags_t current = GET_MODIFIERS; SET_MODIFIERS(explicit_modifiers); @@ -282,7 +293,11 @@ int zmk_hid_masked_modifiers_set(zmk_mod_flags_t new_masked_modifiers) { return current == GET_MODIFIERS ? 0 : 1; } +<<<<<<< HEAD int zmk_hid_masked_modifiers_clear(void) { +======= +int zmk_hid_masked_modifiers_clear() { +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 masked_modifiers = 0; zmk_mod_flags_t current = GET_MODIFIERS; SET_MODIFIERS(explicit_modifiers); @@ -369,11 +384,17 @@ bool zmk_hid_is_pressed(uint32_t usage) { return false; } +<<<<<<< HEAD #if IS_ENABLED(CONFIG_ZMK_MOUSE) // Keep track of how often a button was pressed. // Only release the button if the count is 0. static int explicit_button_counts[5] = {0, 0, 0, 0, 0}; +======= +// Keep track of how often a button was pressed. +// Only release the button if the count is 0. +static int explicit_button_counts[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 static zmk_mod_flags_t explicit_buttons = 0; #define SET_MOUSE_BUTTONS(btns) \ @@ -383,10 +404,13 @@ static zmk_mod_flags_t explicit_buttons = 0; } int zmk_hid_mouse_button_press(zmk_mouse_button_t button) { +<<<<<<< HEAD if (button >= ZMK_HID_MOUSE_NUM_BUTTONS) { return -EINVAL; } +======= +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 explicit_button_counts[button]++; LOG_DBG("Button %d count %d", button, explicit_button_counts[button]); WRITE_BIT(explicit_buttons, button, true); @@ -395,10 +419,13 @@ int zmk_hid_mouse_button_press(zmk_mouse_button_t button) { } int zmk_hid_mouse_button_release(zmk_mouse_button_t button) { +<<<<<<< HEAD if (button >= ZMK_HID_MOUSE_NUM_BUTTONS) { return -EINVAL; } +======= +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 if (explicit_button_counts[button] <= 0) { LOG_ERR("Tried to release button %d too often", button); return -EINVAL; @@ -414,8 +441,13 @@ int zmk_hid_mouse_button_release(zmk_mouse_button_t button) { } int zmk_hid_mouse_buttons_press(zmk_mouse_button_flags_t buttons) { +<<<<<<< HEAD for (zmk_mouse_button_t i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) { if (buttons & BIT(i)) { +======= + for (zmk_mod_t i = 0; i < 16; i++) { + if (buttons & (1 << i)) { +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 zmk_hid_mouse_button_press(i); } } @@ -423,18 +455,55 @@ int zmk_hid_mouse_buttons_press(zmk_mouse_button_flags_t buttons) { } int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons) { +<<<<<<< HEAD for (zmk_mouse_button_t i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) { if (buttons & BIT(i)) { +======= + for (zmk_mod_t i = 0; i < 16; i++) { + if (buttons & (1 << i)) { +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 zmk_hid_mouse_button_release(i); } } return 0; } +<<<<<<< HEAD void zmk_hid_mouse_clear(void) { memset(&mouse_report.body, 0, sizeof(mouse_report.body)); } #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report(void) { +======= + +void zmk_hid_mouse_movement_set(int16_t x, int16_t y) { + mouse_report.body.x = x; + mouse_report.body.y = y; + LOG_DBG("Mouse movement set to 0x%02X 0x%02X ", mouse_report.body.x, mouse_report.body.y); +} + +void zmk_hid_mouse_movement_update(int16_t x, int16_t y) { + mouse_report.body.x += x; + mouse_report.body.y += y; + LOG_DBG("Mouse movement updated to 0x%02X 0x%02X ", mouse_report.body.x, mouse_report.body.y); +} + +void zmk_hid_mouse_scroll_set(int8_t x, int8_t y) { + mouse_report.body.scroll_x = x; + mouse_report.body.scroll_y = y; + LOG_DBG("Mouse scroll set to 0x%02X 0x%02X ", mouse_report.body.scroll_x, + mouse_report.body.scroll_y); +} + +void zmk_hid_mouse_scroll_update(int8_t x, int8_t y) { + mouse_report.body.scroll_x += x / 8; + mouse_report.body.scroll_y += y / 8 ; + LOG_DBG("Mouse scroll updated to 0x%02X 0x%02X ", mouse_report.body.scroll_x, + mouse_report.body.scroll_y); +} +void zmk_hid_mouse_clear() { memset(&mouse_report.body, 0, sizeof(mouse_report.body)); } + +struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report() { +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 return &keyboard_report; } @@ -442,6 +511,7 @@ struct zmk_hid_consumer_report *zmk_hid_get_consumer_report(void) { return &consumer_report; } +<<<<<<< HEAD #if IS_ENABLED(CONFIG_ZMK_MOUSE) struct zmk_hid_mouse_report *zmk_hid_get_mouse_report(void) { @@ -449,3 +519,8 @@ struct zmk_hid_mouse_report *zmk_hid_get_mouse_report(void) { } #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) +======= +struct zmk_hid_mouse_report *zmk_hid_get_mouse_report() { + return &mouse_report; +} +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 diff --git a/app/src/hid_listener.c b/app/src/hid_listener.c index 2b8470820a1..199deeea1ea 100644 --- a/app/src/hid_listener.c +++ b/app/src/hid_listener.c @@ -11,7 +11,6 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include -#include #include #include #include @@ -86,13 +85,14 @@ static int hid_listener_keycode_released(const struct zmk_keycode_state_changed } int hid_listener(const zmk_event_t *eh) { - const struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); - if (ev) { - if (ev->state) { - hid_listener_keycode_pressed(ev); + const struct zmk_keycode_state_changed *kc_ev = as_zmk_keycode_state_changed(eh); + if (kc_ev) { + if (kc_ev->state) { + hid_listener_keycode_pressed(kc_ev); } else { - hid_listener_keycode_released(ev); + hid_listener_keycode_released(kc_ev); } + return 0; } return 0; } diff --git a/app/src/hog.c b/app/src/hog.c index f17f759c908..3d7f1f6fda8 100644 --- a/app/src/hog.c +++ b/app/src/hog.c @@ -69,6 +69,7 @@ static struct hids_report consumer_input = { .type = HIDS_INPUT, }; +<<<<<<< HEAD #if IS_ENABLED(CONFIG_ZMK_MOUSE) static struct hids_report mouse_input = { @@ -78,6 +79,13 @@ static struct hids_report mouse_input = { #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) +======= +static struct hids_report mouse_input = { + .id = 0x04, + .type = HIDS_INPUT, +}; + +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 static bool host_requests_notification = false; static uint8_t ctrl_point; // static uint8_t proto_mode; @@ -143,14 +151,20 @@ static ssize_t read_hids_consumer_input_report(struct bt_conn *conn, sizeof(struct zmk_hid_consumer_report_body)); } +<<<<<<< HEAD #if IS_ENABLED(CONFIG_ZMK_MOUSE) +======= +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 static ssize_t read_hids_mouse_input_report(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { struct zmk_hid_mouse_report_body *report_body = &zmk_hid_get_mouse_report()->body; return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body, sizeof(struct zmk_hid_mouse_report_body)); } +<<<<<<< HEAD #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) +======= +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 // static ssize_t write_proto_mode(struct bt_conn *conn, // const struct bt_gatt_attr *attr, @@ -200,12 +214,16 @@ BT_GATT_SERVICE_DEFINE( BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, NULL, &consumer_input), +<<<<<<< HEAD #if IS_ENABLED(CONFIG_ZMK_MOUSE) +======= +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT, read_hids_mouse_input_report, NULL, NULL), BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, NULL, &mouse_input), +<<<<<<< HEAD #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) #if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) @@ -216,6 +234,8 @@ BT_GATT_SERVICE_DEFINE( BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, NULL, &led_indicators), #endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) +======= +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_CTRL_POINT, BT_GATT_CHRC_WRITE_WITHOUT_RESP, BT_GATT_PERM_WRITE, NULL, write_ctrl_point, &ctrl_point)); @@ -343,8 +363,11 @@ int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report) { return 0; }; +<<<<<<< HEAD #if IS_ENABLED(CONFIG_ZMK_MOUSE) +======= +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 K_MSGQ_DEFINE(zmk_hog_mouse_msgq, sizeof(struct zmk_hid_mouse_report_body), CONFIG_ZMK_BLE_MOUSE_REPORT_QUEUE_SIZE, 4); @@ -363,9 +386,13 @@ void send_mouse_report_callback(struct k_work *work) { }; int err = bt_gatt_notify_cb(conn, ¬ify_params); +<<<<<<< HEAD if (err == -EPERM) { bt_conn_set_security(conn, BT_SECURITY_L2); } else if (err) { +======= + if (err) { +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 LOG_DBG("Error notifying %d", err); } @@ -376,6 +403,7 @@ void send_mouse_report_callback(struct k_work *work) { K_WORK_DEFINE(hog_mouse_work, send_mouse_report_callback); int zmk_hog_send_mouse_report(struct zmk_hid_mouse_report_body *report) { +<<<<<<< HEAD int err = k_msgq_put(&zmk_hog_mouse_msgq, report, K_MSEC(100)); if (err) { switch (err) { @@ -384,6 +412,16 @@ int zmk_hog_send_mouse_report(struct zmk_hid_mouse_report_body *report) { struct zmk_hid_mouse_report_body discarded_report; k_msgq_get(&zmk_hog_mouse_msgq, &discarded_report, K_NO_WAIT); return zmk_hog_send_mouse_report(report); +======= + LOG_DBG("send mouse report using shared queue"); + + int err = k_msgq_put(&zmk_hog_mouse_msgq, report, K_NO_WAIT); + if (err) { + switch (err) { + case -EAGAIN: { + LOG_WRN("Mouse message queue full, dropping report"); + return err; +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } default: LOG_WRN("Failed to queue mouse report to send (%d)", err); @@ -396,9 +434,38 @@ int zmk_hog_send_mouse_report(struct zmk_hid_mouse_report_body *report) { return 0; }; +<<<<<<< HEAD #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) static int zmk_hog_init(void) { +======= +int zmk_hog_send_mouse_report_direct(struct zmk_hid_mouse_report_body *report) { + LOG_DBG("send mouse report directly"); + + struct bt_conn *conn = destination_connection(); + if (conn == NULL) { + return 1; + } + + struct bt_gatt_notify_params notify_params = { + .attr = &hog_svc.attrs[13], + .data = report, + .len = sizeof(*report), + }; + + int err = bt_gatt_notify_cb(conn, ¬ify_params); + if (err) { + LOG_DBG("Error notifying %d", err); + return err; + } + + bt_conn_unref(conn); + + return 0; +}; + +int zmk_hog_init(const struct device *_arg) { +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 static const struct k_work_queue_config queue_config = {.name = "HID Over GATT Send Work"}; k_work_queue_start(&hog_work_q, hog_q_stack, K_THREAD_STACK_SIZEOF(hog_q_stack), CONFIG_ZMK_BLE_THREAD_PRIORITY, &queue_config); diff --git a/app/src/keymap.c b/app/src/keymap.c index 75a2dcbe64b..1a794481871 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -14,7 +14,15 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include +<<<<<<< HEAD #include +======= +#include +#include +#include +#include +#include +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 #include #if ZMK_BLE_IS_CENTRAL @@ -25,6 +33,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include +#include static zmk_keymap_layers_state_t _zmk_keymap_layer_state = 0; static uint8_t _zmk_keymap_layer_default = 0; @@ -34,6 +43,7 @@ static uint8_t _zmk_keymap_layer_default = 0; #define TRANSFORMED_LAYER(node) \ { LISTIFY(DT_PROP_LEN(node, bindings), ZMK_KEYMAP_EXTRACT_BINDING, (, ), node) } +<<<<<<< HEAD #if ZMK_KEYMAP_HAS_SENSORS #define _TRANSFORM_SENSOR_ENTRY(idx, layer) \ { \ @@ -53,6 +63,9 @@ static uint8_t _zmk_keymap_layer_default = 0; #endif /* ZMK_KEYMAP_HAS_SENSORS */ #define LAYER_NAME(node) DT_PROP_OR(node, display_name, DT_PROP_OR(node, label, NULL)) +======= +#define LAYER_LABEL(node) COND_CODE_0(DT_NODE_HAS_PROP(node, label), (NULL), (DT_LABEL(node))), +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 // State @@ -68,7 +81,22 @@ static const char *zmk_keymap_layer_names[ZMK_KEYMAP_LAYERS_LEN] = { DT_INST_FOREACH_CHILD_SEP(0, LAYER_NAME, (, ))}; #if ZMK_KEYMAP_HAS_SENSORS +#define _TRANSFORM_SENSOR_ENTRY(idx, layer) \ + { \ + .behavior_dev = DT_LABEL(DT_PHANDLE_BY_IDX(layer, sensor_bindings, idx)), \ + .param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, sensor_bindings, idx, param1), (0), \ + (DT_PHA_BY_IDX(layer, sensor_bindings, idx, param1))), \ + .param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, sensor_bindings, idx, param2), (0), \ + (DT_PHA_BY_IDX(layer, sensor_bindings, idx, param2))), \ + }, +#define SENSOR_LAYER(node) \ + COND_CODE_1( \ + DT_NODE_HAS_PROP(node, sensor_bindings), \ + ({UTIL_LISTIFY(DT_PROP_LEN(node, sensor_bindings), _TRANSFORM_SENSOR_ENTRY, node)}), \ + ({})), + +<<<<<<< HEAD static struct zmk_behavior_binding zmk_sensor_keymap[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_SENSORS_LEN] = { DT_INST_FOREACH_CHILD_SEP(0, SENSOR_LAYER, (, ))}; @@ -77,6 +105,88 @@ static struct zmk_behavior_binding static inline int set_layer_state(uint8_t layer, bool state) { int ret = 0; +======= +static struct zmk_behavior_binding zmk_sensor_keymap[ZMK_KEYMAP_LAYERS_LEN] + [ZMK_KEYMAP_SENSORS_LEN] = { + DT_INST_FOREACH_CHILD(0, SENSOR_LAYER)}; +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + +#if ZMK_KEYMAP_HAS_SLIDERS +#define _TRANSFORM_SLIDER_ENTRY(idx, layer) \ + { \ + .behavior_dev = DT_LABEL(DT_PHANDLE_BY_IDX(layer, slider_bindings, idx)), \ + .param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, slider_bindings, idx, param1), (0), \ + (DT_PHA_BY_IDX(layer, slider_bindings, idx, param1))), \ + .param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, slider_bindings, idx, param2), (0), \ + (DT_PHA_BY_IDX(layer, slider_bindings, idx, param2))), \ + }, + +#define SLIDER_LAYER(node) \ + COND_CODE_1( \ + DT_NODE_HAS_PROP(node, slider_bindings), \ + ({UTIL_LISTIFY(DT_PROP_LEN(node, slider_bindings), _TRANSFORM_SLIDER_ENTRY, node)}), \ + ({})), + +static struct zmk_behavior_binding zmk_slider_keymap[ZMK_KEYMAP_LAYERS_LEN] + [ZMK_KEYMAP_SLIDERS_LEN] = { + DT_INST_FOREACH_CHILD(0, SLIDER_LAYER)}; + +#endif /* ZMK_KEYMAP_HAS_SLIDERS */ + +#if ZMK_KEYMAP_HAS_TRACKBALLS +#define _TRANSFORM_TRACKBALL_ENTRY(idx, layer) \ + { \ + .behavior_dev = DT_LABEL(DT_PHANDLE_BY_IDX(layer, trackball_bindings, idx)), \ + .param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, trackball_bindings, idx, param1), (0), \ + (DT_PHA_BY_IDX(layer, trackball_bindings, idx, param1))), \ + .param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, trackball_bindings, idx, param2), (0), \ + (DT_PHA_BY_IDX(layer, trackball_bindings, idx, param2))), \ + .param3 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, trackball_bindings, idx, param3), (0), \ + (DT_PHA_BY_IDX(layer, trackball_bindings, idx, param3))), \ + .param4 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, trackball_bindings, idx, param4), (0), \ + (DT_PHA_BY_IDX(layer, trackball_bindings, idx, param4))), \ + }, + +#define TRACKBALL_LAYER(node) \ + COND_CODE_1( \ + DT_NODE_HAS_PROP(node, trackball_bindings), \ + ({UTIL_LISTIFY(DT_PROP_LEN(node, trackball_bindings), _TRANSFORM_TRACKBALL_ENTRY, node)}), \ + ({})), + +static struct zmk_behavior_binding zmk_trackball_keymap[ZMK_KEYMAP_LAYERS_LEN] + [ZMK_KEYMAP_TRACKBALLS_LEN] = { + DT_INST_FOREACH_CHILD(0, TRACKBALL_LAYER)}; + +#endif /* ZMK_KEYMAP_HAS_TRACKBALLS */ + +#if ZMK_KEYMAP_HAS_JOYSTICKS +#define _TRANSFORM_JOYSTICK_ENTRY(idx, layer) \ + { \ + .behavior_dev = DT_LABEL(DT_PHANDLE_BY_IDX(layer, joystick_bindings, idx)), \ + .param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, joystick_bindings, idx, param1), (0), \ + (DT_PHA_BY_IDX(layer, joystick_bindings, idx, param1))), \ + .param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, joystick_bindings, idx, param2), (0), \ + (DT_PHA_BY_IDX(layer, joystick_bindings, idx, param2))), \ + .param3 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, joystick_bindings, idx, param3), (0), \ + (DT_PHA_BY_IDX(layer, joystick_bindings, idx, param3))), \ + .param4 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, joystick_bindings, idx, param4), (0), \ + (DT_PHA_BY_IDX(layer, joystick_bindings, idx, param4))), \ + }, + +#define JOYSTICK_LAYER(node) \ + COND_CODE_1( \ + DT_NODE_HAS_PROP(node, joystick_bindings), \ + ({UTIL_LISTIFY(DT_PROP_LEN(node, joystick_bindings), _TRANSFORM_JOYSTICK_ENTRY, node)}), \ + ({})), + +static struct zmk_behavior_binding zmk_joystick_keymap[ZMK_KEYMAP_LAYERS_LEN] + [ZMK_KEYMAP_JOYSTICKS_LEN] = { + DT_INST_FOREACH_CHILD(0, JOYSTICK_LAYER)}; + +#endif /* ZMK_KEYMAP_HAS_JOYSTICKS */ + +static inline int set_layer_state(uint8_t layer, bool state, bool flag_event) { +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 if (layer >= ZMK_KEYMAP_LAYERS_LEN) { return -EINVAL; } @@ -89,7 +199,7 @@ static inline int set_layer_state(uint8_t layer, bool state) { zmk_keymap_layers_state_t old_state = _zmk_keymap_layer_state; WRITE_BIT(_zmk_keymap_layer_state, layer, state); // Don't send state changes unless there was an actual change - if (old_state != _zmk_keymap_layer_state) { + if (flag_event && (old_state != _zmk_keymap_layer_state)) { LOG_DBG("layer_changed: layer %d state %d", layer, state); ret = raise_layer_state_changed(layer, state); if (ret < 0) { @@ -123,9 +233,13 @@ uint8_t zmk_keymap_highest_layer_active(void) { return zmk_keymap_layer_default(); } -int zmk_keymap_layer_activate(uint8_t layer) { return set_layer_state(layer, true); }; +int zmk_keymap_layer_activate(uint8_t layer) { return set_layer_state(layer, true, true); }; + +int zmk_keymap_layer_deactivate(uint8_t layer) { return set_layer_state(layer, false, true); }; -int zmk_keymap_layer_deactivate(uint8_t layer) { return set_layer_state(layer, false); }; +int zmk_keymap_layer_activate_noevent(uint8_t layer) { return set_layer_state(layer, true, false); }; + +int zmk_keymap_layer_deactivate_noevent(uint8_t layer) { return set_layer_state(layer, false, false); }; int zmk_keymap_layer_toggle(uint8_t layer) { if (zmk_keymap_layer_active(layer)) { @@ -249,10 +363,20 @@ int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pr } #if ZMK_KEYMAP_HAS_SENSORS +<<<<<<< HEAD int zmk_keymap_sensor_event(uint8_t sensor_index, const struct zmk_sensor_channel_data *channel_data, size_t channel_data_size, int64_t timestamp) { bool opaque_response = false; +======= +inline static int zmk_keymap_sensor_triggered(uint8_t sensor_number, const struct sensor_value value, + int64_t timestamp) { + for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= _zmk_keymap_layer_default; layer--) { + if (zmk_keymap_layer_active(layer) && zmk_sensor_keymap[layer] != NULL) { + struct zmk_behavior_binding *binding = &zmk_sensor_keymap[layer][sensor_number]; + const struct device *behavior; + int ret; +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= 0; layer--) { struct zmk_behavior_binding *binding = &zmk_sensor_keymap[layer][sensor_index]; @@ -266,11 +390,15 @@ int zmk_keymap_sensor_event(uint8_t sensor_index, continue; } +<<<<<<< HEAD struct zmk_behavior_binding_event event = { .layer = layer, .position = ZMK_VIRTUAL_KEY_POSITION_SENSOR(sensor_index), .timestamp = timestamp, }; +======= + ret = behavior_sensor_keymap_binding_triggered(binding, value, timestamp); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 int ret = behavior_sensor_keymap_binding_accept_data( binding, event, zmk_sensors_get_config_at_index(sensor_index), channel_data_size, @@ -305,6 +433,120 @@ int zmk_keymap_sensor_event(uint8_t sensor_index, #endif /* ZMK_KEYMAP_HAS_SENSORS */ +#if ZMK_KEYMAP_HAS_SLIDERS +inline static int zmk_keymap_slider_triggered(uint8_t id, int16_t dx, int16_t dy, int dt, + int64_t timestamp) +{ + for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= _zmk_keymap_layer_default; layer--) { + if (zmk_keymap_layer_active(layer) && zmk_slider_keymap[layer] != NULL) { + struct zmk_behavior_binding *binding = &zmk_slider_keymap[layer][id]; + const struct device *behavior; + int ret; + + LOG_INF("layer: %d slider_id: %d, binding name: %s", layer, id, + log_strdup(binding->behavior_dev)); + + behavior = device_get_binding(binding->behavior_dev); + + if (!behavior) { + LOG_DBG("No behavior assigned to %d on layer %d", id, layer); + continue; + } + + ret = behavior_pd_keymap_binding_triggered(binding, dx, dy, dt, timestamp); + + if (ret > 0) { + LOG_DBG("behavior processing to continue to next layer"); + continue; + } else if (ret < 0) { + LOG_DBG("Behavior returned error: %d", ret); + return ret; + } else { + return ret; + } + } + } + + return -ENOTSUP; +} +#endif /* ZMK_KEYMAP_HAS_SLIDERS */ + +#if ZMK_KEYMAP_HAS_TRACKBALLS +inline static int zmk_keymap_trackball_triggered(uint8_t id, int16_t dx, int16_t dy, int dt, + int64_t timestamp) +{ + for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= _zmk_keymap_layer_default; layer--) { + if (zmk_keymap_layer_active(layer) && zmk_trackball_keymap[layer] != NULL) { + struct zmk_behavior_binding *binding = &zmk_trackball_keymap[layer][id]; + const struct device *behavior; + int ret; + + LOG_INF("layer: %d slider_id: %d, binding name: %s", layer, id, + log_strdup(binding->behavior_dev)); + + behavior = device_get_binding(binding->behavior_dev); + + if (!behavior) { + LOG_DBG("No behavior assigned to %d on layer %d", id, layer); + continue; + } + + ret = behavior_pd_keymap_binding_triggered(binding, dx, dy, dt, timestamp); + + if (ret > 0) { + LOG_DBG("behavior processing to continue to next layer"); + continue; + } else if (ret < 0) { + LOG_DBG("Behavior returned error: %d", ret); + return ret; + } else { + return ret; + } + } + } + + return -ENOTSUP; +} +#endif /* ZMK_KEYMAP_HAS_TRACKBALLS */ + +#if ZMK_KEYMAP_HAS_JOYSTICKS +inline static int zmk_keymap_joystick_triggered(uint8_t id, int16_t dx, int16_t dy, int dt, + int64_t timestamp) +{ + for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= _zmk_keymap_layer_default; layer--) { + if (zmk_keymap_layer_active(layer) && zmk_joystick_keymap[layer] != NULL) { + struct zmk_behavior_binding *binding = &zmk_joystick_keymap[layer][id]; + const struct device *behavior; + int ret; + + LOG_INF("layer: %d slider_id: %d, binding name: %s", layer, id, + log_strdup(binding->behavior_dev)); + + behavior = device_get_binding(binding->behavior_dev); + + if (!behavior) { + LOG_DBG("No behavior assigned to %d on layer %d", id, layer); + continue; + } + + ret = behavior_pd_keymap_binding_triggered(binding, dx, dy, dt, timestamp); + + if (ret > 0) { + LOG_DBG("behavior processing to continue to next layer"); + continue; + } else if (ret < 0) { + LOG_DBG("Behavior returned error: %d", ret); + return ret; + } else { + return ret; + } + } + } + + return -ENOTSUP; +} +#endif /* ZMK_KEYMAP_HAS_JOYSTICKS */ + int keymap_listener(const zmk_event_t *eh) { const struct zmk_position_state_changed *pos_ev; if ((pos_ev = as_zmk_position_state_changed(eh)) != NULL) { @@ -315,11 +557,37 @@ int keymap_listener(const zmk_event_t *eh) { #if ZMK_KEYMAP_HAS_SENSORS const struct zmk_sensor_event *sensor_ev; if ((sensor_ev = as_zmk_sensor_event(eh)) != NULL) { +<<<<<<< HEAD return zmk_keymap_sensor_event(sensor_ev->sensor_index, sensor_ev->channel_data, sensor_ev->channel_data_size, sensor_ev->timestamp); +======= + return zmk_keymap_sensor_triggered(sensor_ev->sensor_number, sensor_ev->value, + sensor_ev->timestamp); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } #endif /* ZMK_KEYMAP_HAS_SENSORS */ + const struct zmk_pd_raw_event *pd_ev; + if ((pd_ev = as_zmk_pd_raw_event(eh)) != NULL) { + switch (pd_ev->type) { +#if ZMK_KEYMAP_HAS_SLIDERS + case SLIDER: + return zmk_keymap_slider_triggered(pd_ev->id, pd_ev->dx, pd_ev->dy, pd_ev->dt, pd_ev->update_time); +#endif /* ZMK_KEYMAP_HAS_SLIDERS */ +#if ZMK_KEYMAP_HAS_TRACKBALLS + case TRACKBALL: + return zmk_keymap_trackball_triggered(pd_ev->id, pd_ev->dx, pd_ev->dy, pd_ev->dt, + pd_ev->update_time); +#endif /* ZMK_KEYMAP_HAS_TRACKBALLS */ +#if ZMK_KEYMAP_HAS_JOYSTICKS + case JOYSTICK: + return zmk_keymap_joystick_triggered(pd_ev->id, pd_ev->dx, pd_ev->dy, pd_ev->dt, + pd_ev->update_time); +#endif /* ZMK_KEYMAP_HAS_JOYSTICKS */ + default: + break; + } + } return -ENOTSUP; } @@ -329,3 +597,7 @@ ZMK_SUBSCRIPTION(keymap, zmk_position_state_changed); #if ZMK_KEYMAP_HAS_SENSORS ZMK_SUBSCRIPTION(keymap, zmk_sensor_event); #endif /* ZMK_KEYMAP_HAS_SENSORS */ + +#if defined(ZMK_KEYMAP_HAS_SLIDERS) || defined(ZMK_KEYMAP_HAS_TRACKBALLS) || defined(ZMK_KEYMAP_HAS_JOYSTICKS) +ZMK_SUBSCRIPTION(keymap, zmk_pd_raw_event); +#endif diff --git a/app/src/main.c b/app/src/main.c index 9bd7af32723..dfafd2a796f 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -17,7 +17,21 @@ LOG_MODULE_REGISTER(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include +<<<<<<< HEAD int main(void) { +======= +#ifdef CONFIG_ZMK_MOUSE +#include +#endif /* CONFIG_ZMK_MOUSE */ + +#ifdef CONFIG_ZMK_POINT_DEVICE +#include +#endif /* CONFIG_ZMK_POINT_DEVICE */ + +#define ZMK_KSCAN_DEV DT_LABEL(ZMK_MATRIX_NODE_ID) + +void main(void) { +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 LOG_INF("Welcome to ZMK!\n"); if (zmk_kscan_init(DEVICE_DT_GET(ZMK_MATRIX_NODE_ID)) != 0) { @@ -28,5 +42,15 @@ int main(void) { zmk_display_init(); #endif /* CONFIG_ZMK_DISPLAY */ +<<<<<<< HEAD return 0; +======= +#ifdef CONFIG_ZMK_MOUSE + zmk_mouse_init(); +#endif /* CONFIG_ZMK_MOUSE */ + +#ifdef CONFIG_ZMK_POINT_DEVICE + zmk_pd_init(); +#endif /* CONFIG_ZMK_POINT_DEVICE */ +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } diff --git a/app/src/mouse/Kconfig b/app/src/mouse/Kconfig new file mode 100644 index 00000000000..1161b86b429 --- /dev/null +++ b/app/src/mouse/Kconfig @@ -0,0 +1,38 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +menuconfig ZMK_MOUSE + bool "Enable ZMK mouse emulation" + default n + +config ZMK_MOUSE_TICK_DURATION + int "Mouse tick duration in ms" + default 8 + +if ZMK_MOUSE + +choice ZMK_MOUSE_WORK_QUEUE + prompt "Work queue selection for mouse events" + default ZMK_MOUSE_WORK_QUEUE_DEDICATED + +config ZMK_MOUSE_WORK_QUEUE_SYSTEM + bool "Use default system work queue for mouse events" + +config ZMK_MOUSE_WORK_QUEUE_DEDICATED + bool "Use dedicated work queue for mouse events" + +endchoice + +if ZMK_MOUSE_WORK_QUEUE_DEDICATED + +config ZMK_MOUSE_DEDICATED_THREAD_STACK_SIZE + int "Stack size for dedicated mouse thread/queue" + default 2048 + +config ZMK_MOUSE_DEDICATED_THREAD_PRIORITY + int "Thread priority for dedicated mouse thread/queue" + default 3 + +endif # ZMK_MOUSE_WORK_QUEUE_DEDICATED + +endif diff --git a/app/src/mouse/key_listener.c b/app/src/mouse/key_listener.c new file mode 100644 index 00000000000..fd25543e198 --- /dev/null +++ b/app/src/mouse/key_listener.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) +static struct vector2d move_speed = {0}; +static struct vector2d scroll_speed = {0}; +static struct mouse_config move_config = (struct mouse_config){0}; +static struct mouse_config scroll_config = (struct mouse_config){0}; +static int64_t start_time = 0; + + +#if IS_ENABLED(CONFIG_ZMK_USB_LOGGING) +// in us +static int64_t last_update_time = 0; +static int64_t current_update_time = 0; +static int64_t update_duration = 0; +static int64_t send_report_time = 0; +static int64_t idle_interval = 0; +static int64_t time_buffer = 0; +#endif + +bool equals(const struct mouse_config *one, const struct mouse_config *other) { + return one->delay_ms == other->delay_ms && + one->time_to_max_speed_ms == other->time_to_max_speed_ms && + one->acceleration_exponent == other->acceleration_exponent; +} + +static void clear_mouse_state(struct k_work *work) { + move_speed = (struct vector2d){0}; + scroll_speed = (struct vector2d){0}; + start_time = 0; + zmk_hid_mouse_movement_set(0, 0); + zmk_hid_mouse_scroll_set(0, 0); + LOG_DBG("Clearing state"); +} + +K_WORK_DEFINE(mouse_clear, &clear_mouse_state); + +void mouse_clear_cb(struct k_timer *dummy) { + k_work_submit_to_queue(zmk_mouse_work_q(), &mouse_clear); +} + +static void mouse_tick_timer_handler(struct k_work *work) { +#if IS_ENABLED(CONFIG_ZMK_USB_LOGGING) + current_update_time = k_ticks_to_us_floor64(k_uptime_ticks()); + idle_interval = current_update_time - time_buffer; +#endif + + zmk_hid_mouse_movement_set(0, 0); + zmk_hid_mouse_scroll_set(0, 0); + + LOG_DBG("Raising mouse tick event"); + ZMK_EVENT_RAISE( + zmk_mouse_tick(move_speed, scroll_speed, move_config, scroll_config, &start_time)); + +#if IS_ENABLED(CONFIG_ZMK_USB_LOGGING) + send_report_time = k_ticks_to_us_floor64(k_uptime_ticks()); +#endif + + zmk_endpoints_send_mouse_report(); + +#if IS_ENABLED(CONFIG_ZMK_USB_LOGGING) + time_buffer = k_ticks_to_us_floor64(k_uptime_ticks()); + update_duration = time_buffer - current_update_time; + LOG_DBG("Interrupt duration: %lld ; update: %lld ; report: %lld ; idle: %lld", \ + (current_update_time - last_update_time), update_duration, \ + (time_buffer - send_report_time), idle_interval); + + last_update_time = current_update_time; +#endif +} + +K_WORK_DEFINE(mouse_tick, &mouse_tick_timer_handler); + +void mouse_timer_cb(struct k_timer *dummy) { + LOG_DBG("Submitting mouse work to queue"); + k_work_submit_to_queue(zmk_mouse_work_q(), &mouse_tick); +} + +K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, mouse_clear_cb); + +static int mouse_timer_ref_count = 0; + +void mouse_timer_ref() { + if (mouse_timer_ref_count == 0) { + start_time = k_uptime_get(); + k_timer_start(&mouse_timer, K_NO_WAIT, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION)); + } + mouse_timer_ref_count += 1; +} + +void mouse_timer_unref() { + if (mouse_timer_ref_count > 0) { + mouse_timer_ref_count--; + } + if (mouse_timer_ref_count == 0) { + k_timer_stop(&mouse_timer); + } +} + +static void listener_mouse_move_pressed(const struct zmk_mouse_move_state_changed *ev) { + move_speed.x += ev->max_speed.x; + move_speed.y += ev->max_speed.y; + mouse_timer_ref(); +} + +static void listener_mouse_move_released(const struct zmk_mouse_move_state_changed *ev) { + move_speed.x -= ev->max_speed.x; + move_speed.y -= ev->max_speed.y; + mouse_timer_unref(); +} + +static void listener_mouse_scroll_pressed(const struct zmk_mouse_scroll_state_changed *ev) { + scroll_speed.x += ev->max_speed.x; + scroll_speed.y += ev->max_speed.y; + mouse_timer_ref(); +} + +static void listener_mouse_scroll_released(const struct zmk_mouse_scroll_state_changed *ev) { + scroll_speed.x -= ev->max_speed.x; + scroll_speed.y -= ev->max_speed.y; + mouse_timer_unref(); +} + +static void listener_mouse_button_pressed(const struct zmk_mouse_button_state_changed *ev) { + LOG_DBG("buttons: 0x%02X", ev->buttons); + zmk_hid_mouse_buttons_press(ev->buttons); + zmk_endpoints_send_mouse_report(); +} + +static void listener_mouse_button_released(const struct zmk_mouse_button_state_changed *ev) { + LOG_DBG("buttons: 0x%02X", ev->buttons); + zmk_hid_mouse_buttons_release(ev->buttons); + zmk_endpoints_send_mouse_report(); +} + +int mouse_listener(const zmk_event_t *eh) { + const struct zmk_mouse_move_state_changed *mmv_ev = as_zmk_mouse_move_state_changed(eh); + if (mmv_ev) { + if (!equals(&move_config, &(mmv_ev->config))) + move_config = mmv_ev->config; + + if (mmv_ev->state) { + listener_mouse_move_pressed(mmv_ev); + } else { + listener_mouse_move_released(mmv_ev); + } + return 0; + } + const struct zmk_mouse_scroll_state_changed *msc_ev = as_zmk_mouse_scroll_state_changed(eh); + if (msc_ev) { + if (!equals(&scroll_config, &(msc_ev->config))) + scroll_config = msc_ev->config; + if (msc_ev->state) { + listener_mouse_scroll_pressed(msc_ev); + } else { + listener_mouse_scroll_released(msc_ev); + } + return 0; + } + const struct zmk_mouse_button_state_changed *mbt_ev = as_zmk_mouse_button_state_changed(eh); + if (mbt_ev) { + if (mbt_ev->state) { + listener_mouse_button_pressed(mbt_ev); + } else { + listener_mouse_button_released(mbt_ev); + } + return 0; + } + return 0; +} + +ZMK_LISTENER(mouse_listener, mouse_listener); +ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_button_state_changed); +ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_move_state_changed); +ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_scroll_state_changed); + +#endif /*!defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */ diff --git a/app/src/mouse/main.c b/app/src/mouse/main.c new file mode 100644 index 00000000000..ee759171736 --- /dev/null +++ b/app/src/mouse/main.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) +K_THREAD_STACK_DEFINE(mouse_work_stack_area, CONFIG_ZMK_MOUSE_DEDICATED_THREAD_STACK_SIZE); +static struct k_work_q mouse_work_q; +#endif + +struct k_work_q *zmk_mouse_work_q() { +#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) + return &mouse_work_q; +#else + return &k_sys_work_q; +#endif +} + +int zmk_mouse_init() { +#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) + k_work_queue_start(&mouse_work_q, mouse_work_stack_area, + K_THREAD_STACK_SIZEOF(mouse_work_stack_area), + CONFIG_ZMK_MOUSE_DEDICATED_THREAD_PRIORITY, + NULL); +#endif + return 0; +} \ No newline at end of file diff --git a/app/src/mouse/tick_listener.c b/app/src/mouse/tick_listener.c new file mode 100644 index 00000000000..996563184b8 --- /dev/null +++ b/app/src/mouse/tick_listener.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include + +#include // CLAMP + +#if !defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) +#if CONFIG_MINIMAL_LIBC +static float powf(float base, float exponent) { + // poor man's power implementation rounds the exponent down to the nearest integer. + float power = 1.0f; + for (; exponent >= 1.0f; exponent--) { + power = power * base; + } + return power; +} +#else +#include +#endif + +struct vector2d move_remainder = {0}; +struct vector2d scroll_remainder = {0}; + +static int64_t ms_since_start(int64_t start, int64_t now, int64_t delay) { + int64_t move_duration = now - (start + delay); + // start can be in the future if there's a delay + if (move_duration < 0) { + move_duration = 0; + } + return move_duration; +} + +static float speed(const struct mouse_config *config, float max_speed, int64_t duration_ms) { + // Calculate the speed based on MouseKeysAccel + // See https://en.wikipedia.org/wiki/Mouse_keys + if (duration_ms > config->time_to_max_speed_ms || config->time_to_max_speed_ms == 0 || + config->acceleration_exponent == 0) { + return max_speed; + } + float time_fraction = (float)duration_ms / config->time_to_max_speed_ms; + return max_speed * powf(time_fraction, config->acceleration_exponent); +} + +static void track_remainder(float *move, float *remainder) { + float new_move = *move + *remainder; + *remainder = new_move - (int)new_move; + *move = (int)new_move; +} + +static struct vector2d update_movement(struct vector2d *remainder, + const struct mouse_config *config, struct vector2d max_speed, + int64_t now, int64_t *start_time) { + struct vector2d move = {0}; + if (max_speed.x == 0 && max_speed.y == 0) { + *remainder = (struct vector2d){0}; + return move; + } + + int64_t move_duration = ms_since_start(*start_time, now, config->delay_ms); + move = (struct vector2d){ + .x = speed(config, max_speed.x, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, + .y = speed(config, max_speed.y, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, + }; + + track_remainder(&(move.x), &(remainder->x)); + track_remainder(&(move.y), &(remainder->y)); + + return move; +} + +static void mouse_tick_handler(const struct zmk_mouse_tick *tick) { + struct vector2d move = update_movement(&move_remainder, &(tick->move_config), tick->max_move, + tick->timestamp, tick->start_time); + zmk_hid_mouse_movement_update((int16_t)CLAMP(move.x, INT16_MIN, INT16_MAX), + (int16_t)CLAMP(move.y, INT16_MIN, INT16_MAX)); + struct vector2d scroll = update_movement(&scroll_remainder, &(tick->scroll_config), + tick->max_scroll, tick->timestamp, tick->start_time); + zmk_hid_mouse_scroll_update((int8_t)CLAMP(scroll.x, INT8_MIN, INT8_MAX), + (int8_t)CLAMP(scroll.y, INT8_MIN, INT8_MAX)); +} + +int zmk_mouse_tick_listener(const zmk_event_t *eh) { + const struct zmk_mouse_tick *tick = as_zmk_mouse_tick(eh); + if (tick) { + mouse_tick_handler(tick); + return 0; + } + return 0; +} + +ZMK_LISTENER(zmk_mouse_tick_listener, zmk_mouse_tick_listener); +ZMK_SUBSCRIPTION(zmk_mouse_tick_listener, zmk_mouse_tick); + +#endif /* !defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */ diff --git a/app/src/point_device/Kconfig b/app/src/point_device/Kconfig new file mode 100644 index 00000000000..9e26ec3d9f3 --- /dev/null +++ b/app/src/point_device/Kconfig @@ -0,0 +1,86 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +DT_COMPAT_ZMK_KEYMAP_TRACKBALLS := zmk,keymap-trackballs +DT_COMPAT_ZMK_KEYMAP_SLIDERS := zmk,keymap-sliders + +menuconfig ZMK_POINT_DEVICE + bool "Enable support for ZMK general point device" + default n + +if ZMK_POINT_DEVICE + +choice ZMK_PD_WORK_QUEUE + prompt "Work queue used to process point device events" + +config ZMK_PD_WORK_QUEUE_DEDICATED + bool "Use dedicated work queue for point device events" + +config ZMK_PD_WORK_QUEUE_SYSTEM + bool "Use default system work queue for point device events" +endchoice + +if ZMK_PD_WORK_QUEUE_DEDICATED + +config ZMK_PD_DEDICATED_WORK_QUEUE_STACK_SIZE + int "Stack size for dedicated point device thread/queue" + default 2048 + +config ZMK_PD_DEDICATED_WORK_QUEUE_PRIORITY + int "Thread priority for dedicated point device thread/queue" + default 2 + +endif # ZMK_PD_WORK_QUEUE_DEDICATED + +choice ZMK_PD_SEND_THREAD + prompt "Thread used to send mouse report" + +config ZMK_PD_SEND_THREAD_DEDICATED + bool "Use dedicated thread to send mouse report" + +config ZMK_PD_SEND_THREAD_SHARED + bool "Use default zmk work queue to send mouse report" +endchoice + +if ZMK_PD_SEND_THREAD_DEDICATED + +config ZMK_PD_DEDICATED_SEND_THREAD_STACK_SIZE + int "Stack size for dedicated point device sending thread" + default 2048 + +config ZMK_PD_DEDICATED_SEND_THREAD_PRIORITY + int "Thread priority for dedicated point device sending thread" + default -1 + +endif # ZMK_PD_SEND_THREAD_DEDICATED + +config ZMK_BHV_PD_DIR_TIME_WINDOW + int "Time window (ms) of directional behavior of point device" + default 300 + +endif # ZMK_POINT_DEVICE + +config ZMK_SLIDERS + bool + default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KEYMAP_SLIDERS)) + select ZMK_POINT_DEVICE + +config ZMK_TRACKBALLS + bool + default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KEYMAP_TRACKBALLS)) + select ZMK_POINT_DEVICE + +if ZMK_TRACKBALLS +config ZMK_TRACKBALL_USB_POLL_INTERVAL + int "Poll interval in ms under wired connection" + default 8 + +config ZMK_TRACKBALL_BLE_POLL_INTERVAL + int "Poll interval in ms under bluetooth connection" + default 8 + +config ZMK_TRACKBALL_POLL_DURATION + int "Duration of polling after receiving an interrupt in ms" + default 300 + +endif # ZMK_TRACKBALLS diff --git a/app/src/point_device/main.c b/app/src/point_device/main.c new file mode 100644 index 00000000000..3362b49483c --- /dev/null +++ b/app/src/point_device/main.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#if IS_ENABLED(CONFIG_ZMK_PD_WORK_QUEUE_DEDICATED) +static const struct k_work_queue_config pd_work_q_config = {.name = "Processor for events from all point devices", + .no_yield = false }; +static struct k_work_q pd_work_q; +K_THREAD_STACK_DEFINE(pd_work_stack_area, CONFIG_ZMK_PD_DEDICATED_WORK_QUEUE_STACK_SIZE); +#endif + +struct k_work_q *zmk_pd_work_q() { +#if IS_ENABLED(CONFIG_ZMK_PD_WORK_QUEUE_DEDICATED) + return &pd_work_q; +#else + return &k_sys_work_q; +#endif +} + +int zmk_pd_init() { +#if IS_ENABLED(CONFIG_ZMK_PD_WORK_QUEUE_DEDICATED) + k_work_queue_init(&pd_work_q); + k_work_queue_start(&pd_work_q, pd_work_stack_area, + K_THREAD_STACK_SIZEOF(pd_work_stack_area), + CONFIG_ZMK_PD_DEDICATED_WORK_QUEUE_PRIORITY, + &pd_work_q_config); +#endif + return 0; +} diff --git a/app/src/point_device/pd_listener.c b/app/src/point_device/pd_listener.c new file mode 100644 index 00000000000..ebc75d31a52 --- /dev/null +++ b/app/src/point_device/pd_listener.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +// Listener for position and scroll change + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include + +typedef struct { + int16_t x; + int16_t y; + bool scroll; +}__attribute__((aligned(4))) zmk_pd_msg; + +K_MSGQ_DEFINE(zmk_pd_msgq, sizeof(zmk_pd_msg), CONFIG_ZMK_KSCAN_EVENT_QUEUE_SIZE, 4); + +static void pd_process_msgq(struct k_work *work) { + zmk_pd_msg msg; + + while (k_msgq_get(&zmk_pd_msgq, &msg, K_NO_WAIT) == 0) { + if (msg.scroll) { + LOG_INF("Send pd scroll data (%d, %d)", msg.x, msg.y); + zmk_hid_mouse_scroll_set(0, 0); + zmk_hid_mouse_movement_set(0, 0); + zmk_hid_mouse_scroll_update(msg.x, msg.y); + } + else { + LOG_INF("Send pd position data (%d, %d)", msg.x, msg.y); + zmk_hid_mouse_movement_set(0, 0); + zmk_hid_mouse_scroll_set(0, 0); + zmk_hid_mouse_movement_update(CLAMP(msg.x, INT8_MIN, INT8_MAX), CLAMP(msg.y, INT8_MIN, INT8_MAX)); + } + + zmk_endpoints_send_mouse_report(); + } +} + +K_WORK_DEFINE(pd_msg_processor, pd_process_msgq); + +int pd_listener(const zmk_event_t *eh) { + const struct zmk_pd_position_state_changed *mv_ev = as_zmk_pd_position_state_changed(eh); + if (mv_ev) { + zmk_pd_msg msg = {.x = mv_ev->x, .y = mv_ev->y, .scroll = false}; + k_msgq_put(&zmk_pd_msgq, &msg, K_NO_WAIT); + k_work_submit_to_queue(zmk_mouse_work_q(), &pd_msg_processor); + return 0; + } + + const struct zmk_pd_scroll_state_changed *sc_ev = as_zmk_pd_scroll_state_changed(eh); + if (sc_ev) { + zmk_pd_msg msg = {.x = sc_ev->x, .y = sc_ev->y, .scroll = true}; + k_msgq_put(&zmk_pd_msgq, &msg, K_NO_WAIT); + k_work_submit_to_queue(zmk_mouse_work_q(), &pd_msg_processor); + return 0; + } + return 0; +} + +ZMK_LISTENER(pd_listener, pd_listener); +ZMK_SUBSCRIPTION(pd_listener, zmk_pd_position_state_changed); +ZMK_SUBSCRIPTION(pd_listener, zmk_pd_scroll_state_changed); diff --git a/app/src/point_device/sliders.c b/app/src/point_device/sliders.c new file mode 100644 index 00000000000..f314e9cfd33 --- /dev/null +++ b/app/src/point_device/sliders.c @@ -0,0 +1,86 @@ +/* Description: +* 1. setup sliders callback +* 2. The callback will set up the correct information and raise a slider event +* 3. The processing of slider event is dispatched to listening processors, notably keymap +*/ + +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include + +#include +#include + +#if ZMK_KEYMAP_HAS_SLIDERS + +typedef struct { + uint8_t id; + int16_t dPos; + int dT; +}__attribute__((aligned(4))) zmk_slider_msg; + +K_MSGQ_DEFINE(zmk_slider_msgq, sizeof(zmk_slider_msg), CONFIG_ZMK_KSCAN_EVENT_QUEUE_SIZE, 4); + +/* the slider msg processor */ +void zmk_slider_process_msgq(struct k_work *item) { + zmk_slider_msg msg; + + while (k_msgq_get(&zmk_slider_msgq, &msg, K_NO_WAIT) == 0) { + LOG_INF("Event from slider_%d: dPos: %d, dT: %d ms", msg.id, msg.dPos, msg.dT); + ZMK_EVENT_RAISE(new_zmk_pd_raw_event((struct zmk_pd_raw_event){ + .type = SLIDER, + .id = msg.id, .dx = msg.dPos, .dy = msg.dPos, + .dt = msg.dT, .update_time = k_uptime_get()})); + } +} + +K_WORK_DEFINE(slider_msgq_work, zmk_slider_process_msgq); + +/* the slider callback */ +void zmk_slider_callback(const struct device *dev, int16_t dPos, int dT) +{ + struct slider_data *slider_data = dev->data; + zmk_slider_msg msg = { + .id = slider_data->id, + .dPos = dPos, + .dT = dT + }; + + k_msgq_put(&zmk_slider_msgq, &msg, K_NO_WAIT); + k_work_submit_to_queue(zmk_pd_work_q(), &slider_msgq_work); +} + +/* config the sliders: setup callback and assign the slider id */ +static void zmk_sliders_init_item(const char *node, uint8_t abs_i) { + LOG_DBG("Init %s with slider_id %d", node, abs_i); + + const struct device *dev = device_get_binding(node); + if (!dev) { + LOG_WRN("Failed to find device for %s", node); + return; + } + + kscan_slider_config(dev, zmk_slider_callback, abs_i); +} + +#define SLIDER_INIT(idx, _i) \ + COND_CODE_1(DT_NODE_HAS_STATUS(ZMK_KEYMAP_SLIDERS_BY_IDX(idx), okay), \ + (zmk_sliders_init_item(DT_LABEL(ZMK_KEYMAP_SLIDERS_BY_IDX(idx)), idx);), (;)) + +static int zmk_sliders_init(const struct device *_arg) { + UTIL_LISTIFY(ZMK_KEYMAP_SLIDERS_LEN, SLIDER_INIT, 0) + return 0; +} + +SYS_INIT(zmk_sliders_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); +#endif + diff --git a/app/src/point_device/trackballs.c b/app/src/point_device/trackballs.c new file mode 100644 index 00000000000..7e2059e1722 --- /dev/null +++ b/app/src/point_device/trackballs.c @@ -0,0 +1,238 @@ +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include + +#include +#include +#include +#include +#include + +#if ZMK_KEYMAP_HAS_TRACKBALLS + +static int max_poll_count = 0; +static int polling_interval = 0; + +struct trackballs_data_item { + uint8_t id; + const struct device *dev; + struct sensor_trigger trigger; + struct k_work poll_work; + struct k_timer poll_timer; + int polling_count; + + struct sensor_value dx; + struct sensor_value dy; +}; + +#define _TRACKBALL_ITEM(node) \ + {.dev = NULL, .polling_count=0, .trigger = {.type = SENSOR_TRIG_DATA_READY, .chan = SENSOR_CHAN_ALL}}, +#define TRACKBALL_ITEM(idx, _) \ + COND_CODE_1(DT_NODE_HAS_STATUS(ZMK_KEYMAP_TRACKBALLS_BY_IDX(idx), okay), \ + (_TRACKBALL_ITEM(ZMK_KEYMAP_TRACKBALLS_BY_IDX(idx))), ()) + +static struct trackballs_data_item trackballs[] = {UTIL_LISTIFY(ZMK_KEYMAP_TRACKBALLS_LEN, TRACKBALL_ITEM, 0)}; + +// msg structure +typedef struct { + uint8_t id; + int16_t dx; + int16_t dy; + int dt; +}__attribute__((aligned(4))) zmk_trackballs_msg; + +K_MSGQ_DEFINE(zmk_trackballs_msgq, sizeof(zmk_trackballs_msg), CONFIG_ZMK_KSCAN_EVENT_QUEUE_SIZE, 4); + +/* the msg processor */ +void zmk_trackballs_process_msgq(struct k_work *work) { + zmk_trackballs_msg msg; + while (k_msgq_get(&zmk_trackballs_msgq, &msg, K_NO_WAIT) == 0) { + LOG_INF("Process event from trackball_%d: dx: %d, dy: %d, dt: %d ms", msg.id, msg.dx, msg.dy, msg.dt); + ZMK_EVENT_RAISE(new_zmk_pd_raw_event((struct zmk_pd_raw_event){ + .type = TRACKBALL, + .id = msg.id, .dx = msg.dx, .dy = msg.dy, + .dt = msg.dt, .update_time = k_uptime_get()})); + } +} + +K_WORK_DEFINE(zmk_trackballs_msgq_work, zmk_trackballs_process_msgq); + +// polling work +static void zmk_trackballs_poll_handler(struct k_work *work) { + struct trackballs_data_item *item = CONTAINER_OF(work, struct trackballs_data_item, poll_work); + const struct device *dev = item->dev; + + // fetch dx and dy from sensor and save them into pixart_data structure + int ret = sensor_sample_fetch(dev); + if (ret < 0) { + LOG_ERR("fetch: %d", ret); + return; + } + + // get the x, y delta + ret = sensor_channel_get(dev, SENSOR_CHAN_POS_DX, &item->dx); + if (unlikely(ret < 0)) { + LOG_ERR("get dx: %d", ret); + return; + } + ret = sensor_channel_get(dev, SENSOR_CHAN_POS_DY, &item->dy); + if (unlikely(ret < 0)) { + LOG_ERR("get dy: %d", ret); + return; + } + + // put the msg + zmk_trackballs_msg msg = { + .id = item->id, + .dx = item->dx.val1, + .dy = item->dy.val1, + .dt = polling_interval + }; + + if(msg.dx != 0 || msg.dy != 0) { + LOG_INF("New position received: dx = %d, dy = %d", msg.dx, msg.dy); + k_msgq_put(&zmk_trackballs_msgq, &msg, K_NO_WAIT); + k_work_submit_to_queue(zmk_pd_work_q(), &zmk_trackballs_msgq_work); + } +} + +// trigger handler +static void zmk_trackballs_trigger_handler(const struct device *dev, const struct sensor_trigger *trig) { + LOG_INF("New interrupt received"); + + struct trackballs_data_item *item = CONTAINER_OF(trig, struct trackballs_data_item, trigger); + + // do not resume motion interrupt by passing-in null handler + if (sensor_trigger_set(item->dev, trig, NULL) < 0) { + LOG_ERR("can't stop motion interrupt line"); + }; + + // start the polling timer (the real work now is dispatched to a timer-based polling) + LOG_INF("Polling start ..."); + k_timer_start(&item->poll_timer, K_NO_WAIT, K_MSEC(polling_interval)); +} + +// timer expiry function +void zmk_trackballs_timer_expiry(struct k_timer *timer) { + struct trackballs_data_item *item = CONTAINER_OF(timer, struct trackballs_data_item, poll_timer); + + // check whether reaching the polling count limit + if(item->polling_count < max_poll_count) { + LOG_INF("Poll %d", item->polling_count); + // submit polling work to mouse work queue + k_work_submit_to_queue(zmk_pd_work_q(), &item->poll_work); + + // update status + item->polling_count++; + } + else { + LOG_INF("Polling end."); + // stop timer + k_timer_stop(&item->poll_timer); + } +} + +// timer stop function +void zmk_trackballs_timer_stop(struct k_timer *timer) { + struct trackballs_data_item *item = CONTAINER_OF(timer, struct trackballs_data_item, poll_timer); + + // reset polling count + item->polling_count = 0; + + // resume motion interrupt line by setting the handler to a real object + if (sensor_trigger_set(item->dev, &item->trigger, zmk_trackballs_trigger_handler) < 0) { + LOG_ERR("can't resume motion interrupt line"); + }; +} + +int zmk_trackballs_endpoint_listener(const zmk_event_t *eh) { + LOG_INF("Update polling parameters based on current endpoint"); + + // update polling parameters + switch (zmk_endpoints_selected()) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ZMK_ENDPOINT_USB: { + max_poll_count = CONFIG_ZMK_TRACKBALL_POLL_DURATION / CONFIG_ZMK_TRACKBALL_USB_POLL_INTERVAL; + polling_interval = CONFIG_ZMK_TRACKBALL_USB_POLL_INTERVAL; + break; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB) */ + +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ZMK_ENDPOINT_BLE: { + max_poll_count = CONFIG_ZMK_TRACKBALL_POLL_DURATION / CONFIG_ZMK_TRACKBALL_BLE_POLL_INTERVAL; + polling_interval = CONFIG_ZMK_TRACKBALL_BLE_POLL_INTERVAL; + break; + } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ + default: + LOG_ERR("Unsupported endpoint"); + } + + return ZMK_EV_EVENT_BUBBLE; +} + +static void zmk_trackballs_init_item(const char *node, uint8_t i, uint8_t abs_i) { + LOG_INF("Init %s at index %d with trackball id %d", node, i, abs_i); + + // init item structure + trackballs[i].dev = device_get_binding(node); + trackballs[i].id = abs_i; + + if (!trackballs[i].dev) { + LOG_WRN("Failed to find device for %s", node); + return; + } + + // setup the timer and handler function of the polling work + k_timer_init(&trackballs[i].poll_timer, zmk_trackballs_timer_expiry, zmk_trackballs_timer_stop); + k_work_init(&trackballs[i].poll_work, zmk_trackballs_poll_handler); + + // init trigger handler + int err; + int count = 0; + do { + err = sensor_trigger_set(trackballs[i].dev, &trackballs[i].trigger, zmk_trackballs_trigger_handler); + if (err == -EBUSY) { + count++; + k_sleep(K_MSEC(20)); + } + } while (err == -EBUSY && count < 100); + + if (err) { + LOG_ERR("Cannot enable trigger in app/src/point_device/trackball.c %d ", err); + return; + } + + // init the polling parameters + zmk_trackballs_endpoint_listener(NULL); +} + +#define _TRACKBALL_INIT(node) zmk_trackballs_init_item(DT_LABEL(node), local_index++, absolute_index++); +#define TRACKBALL_INIT(idx, _i) \ + COND_CODE_1(DT_NODE_HAS_STATUS(ZMK_KEYMAP_TRACKBALLS_BY_IDX(idx), okay), \ + (_TRACKBALL_INIT(ZMK_KEYMAP_TRACKBALLS_BY_IDX(idx))), (absolute_index++;)) + +static int zmk_trackballs_init(const struct device *_arg) { + LOG_INF("Init trackballs ..."); + int local_index = 0; + int absolute_index = 0; + + UTIL_LISTIFY(ZMK_KEYMAP_TRACKBALLS_LEN, TRACKBALL_INIT, 0) + return 0; +} + +SYS_INIT(zmk_trackballs_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); + +ZMK_LISTENER(zmk_trackballs, zmk_trackballs_endpoint_listener) +ZMK_SUBSCRIPTION(zmk_trackballs, zmk_endpoint_selection_changed) + +#endif + diff --git a/app/src/sensors.c b/app/src/sensors.c index 4dcda44d1d1..8d2e3b0b9cc 100644 --- a/app/src/sensors.c +++ b/app/src/sensors.c @@ -80,7 +80,19 @@ static void trigger_sensor_data_for_position(uint32_t sensor_index) { } struct sensor_value value; +<<<<<<< HEAD err = sensor_channel_get(item->dev, item->trigger.chan, &value); +======= + err = sensor_channel_get(dev, SENSOR_CHAN_ROTATION, &value); + if (err) { + LOG_WRN("Failed to get sensor rotation value: %d", err); + return; + } + + ZMK_EVENT_RAISE(new_zmk_sensor_event((struct zmk_sensor_event){ + .sensor_number = item->sensor_number, .value = value, .timestamp = k_uptime_get()})); +} +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 if (err) { LOG_WRN("Failed to get channel data from device %d", err); diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index abb37a0b91c..dd75979f5c7 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -27,8 +27,12 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include +<<<<<<< HEAD #include #include +======= +#include +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 static int start_scanning(void); @@ -187,21 +191,41 @@ K_MSGQ_DEFINE(peripheral_sensor_event_msgq, sizeof(struct zmk_sensor_event), void peripheral_sensor_event_work_callback(struct k_work *work) { struct zmk_sensor_event ev; while (k_msgq_get(&peripheral_sensor_event_msgq, &ev, K_NO_WAIT) == 0) { +<<<<<<< HEAD LOG_DBG("Trigger sensor change for %d", ev.sensor_index); raise_zmk_sensor_event(ev); +======= + LOG_DBG("Trigger sensor change for %d", ev.sensor_number); + ZMK_EVENT_RAISE(new_zmk_sensor_event(ev)); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } } K_WORK_DEFINE(peripheral_sensor_event_work, peripheral_sensor_event_work_callback); +<<<<<<< HEAD static uint8_t split_central_sensor_notify_func(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length) { +======= +struct sensor_event { + uint8_t sensor_number; + struct sensor_value value; +}; + +static uint8_t split_central_sensor_notify_func(struct bt_conn *conn, + struct bt_gatt_subscribe_params *params, + const void *data, uint16_t length) { + + const struct sensor_event *sensor_event = data; + +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 if (!data) { LOG_DBG("[UNSUBSCRIBED]"); params->value_handle = 0U; return BT_GATT_ITER_STOP; } +<<<<<<< HEAD LOG_DBG("[SENSOR NOTIFICATION] data %p length %u", data, length); @@ -219,6 +243,15 @@ static uint8_t split_central_sensor_notify_func(struct bt_conn *conn, memcpy(ev.channel_data, sensor_event.channel_data, sizeof(struct zmk_sensor_channel_data) * sensor_event.channel_data_size); +======= + LOG_DBG("[SENSOR NOTIFICATION] data %p length %u", data, length); + + struct zmk_sensor_event ev = { + .sensor_number = sensor_event->sensor_number, + .value = {.val1 = (sensor_event->value).val1, .val2 = (sensor_event->value).val2}, + .timestamp = k_uptime_get()}; + +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 k_msgq_put(&peripheral_sensor_event_msgq, &ev, K_NO_WAIT); k_work_submit(&peripheral_sensor_event_work); @@ -270,6 +303,7 @@ static uint8_t split_central_notify_func(struct bt_conn *conn, return BT_GATT_ITER_CONTINUE; } +<<<<<<< HEAD #if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING) static uint8_t peripheral_battery_levels[ZMK_SPLIT_BLE_PERIPHERAL_COUNT] = {0}; @@ -375,6 +409,9 @@ static uint8_t split_central_battery_level_read_func(struct bt_conn *conn, uint8 #endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING) */ static int split_central_subscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *params) { +======= +static void split_central_subscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *params) { +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 int err = bt_gatt_subscribe(conn, params); switch (err) { case -EALREADY: @@ -391,6 +428,39 @@ static int split_central_subscribe(struct bt_conn *conn, struct bt_gatt_subscrib return err; } +#if ZMK_KEYMAP_HAS_SENSORS +static struct bt_uuid_128 sensor_uuid = BT_UUID_INIT_128(ZMK_SPLIT_BT_SERVICE_UUID); +static struct bt_gatt_discover_params sensor_discover_params; +static struct bt_gatt_subscribe_params sensor_subscribe_params; +static uint8_t split_central_sensor_desc_discovery_func(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + int err; + + if (!bt_uuid_cmp(sensor_discover_params.uuid, + BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID))) { + memcpy(&sensor_uuid, BT_UUID_GATT_CCC, sizeof(sensor_uuid)); + sensor_discover_params.uuid = &sensor_uuid.uuid; + sensor_discover_params.start_handle = attr->handle; + sensor_discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR; + + sensor_subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); + + err = bt_gatt_discover(conn, &sensor_discover_params); + if (err) { + LOG_ERR("Discover failed (err %d)", err); + } + } else { + sensor_subscribe_params.notify = split_central_sensor_notify_func; + sensor_subscribe_params.value = BT_GATT_CCC_NOTIFY; + sensor_subscribe_params.ccc_handle = attr->handle; + split_central_subscribe(conn, &sensor_subscribe_params); + } + + return BT_GATT_ITER_STOP; +} +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { @@ -421,6 +491,7 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn, slot->subscribe_params.notify = split_central_notify_func; slot->subscribe_params.value = BT_GATT_CCC_NOTIFY; split_central_subscribe(conn, &slot->subscribe_params); +<<<<<<< HEAD #if ZMK_KEYMAP_HAS_SENSORS } else if (bt_uuid_cmp(chrc_uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID)) == 0) { @@ -437,6 +508,10 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn, #endif /* ZMK_KEYMAP_HAS_SENSORS */ } else if (bt_uuid_cmp(chrc_uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID)) == 0) { +======= + } else if (!bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid, + BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID))) { +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 LOG_DBG("Found run behavior handle"); slot->discover_params.uuid = NULL; slot->discover_params.start_handle = attr->handle + 2; @@ -514,6 +589,22 @@ static uint8_t split_central_service_discovery_func(struct bt_conn *conn, if (err) { LOG_ERR("Failed to start discovering split service characteristics (err %d)", err); } + +#if ZMK_KEYMAP_HAS_SENSORS + memcpy(&sensor_uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID), + sizeof(sensor_uuid)); + sensor_discover_params.uuid = &sensor_uuid.uuid; + sensor_discover_params.start_handle = attr->handle; + sensor_discover_params.end_handle = 0xffff; + sensor_discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + sensor_discover_params.func = split_central_sensor_desc_discovery_func; + + err = bt_gatt_discover(conn, &sensor_discover_params); + if (err) { + LOG_ERR("Discover failed (err %d)", err); + } +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + return BT_GATT_ITER_STOP; } diff --git a/app/src/split/bluetooth/service.c b/app/src/split/bluetooth/service.c index 505eb363cd8..70b8fe2d891 100644 --- a/app/src/split/bluetooth/service.c +++ b/app/src/split/bluetooth/service.c @@ -4,7 +4,11 @@ * SPDX-License-Identifier: MIT */ +<<<<<<< HEAD #include +======= +#include +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 #include #include #include @@ -21,6 +25,23 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include +#include + +#if ZMK_KEYMAP_HAS_SENSORS +struct sensor_event { + uint8_t sensor_number; + struct sensor_value value; +} sensor_event; + +static ssize_t split_svc_sensor_state(struct bt_conn *conn, const struct bt_gatt_attr *attrs, + void *buf, uint16_t len, uint16_t offset) { + return bt_gatt_attr_read(conn, attrs, buf, len, offset, &sensor_event, sizeof(sensor_event)); +} + +static void split_svc_sensor_state_ccc(const struct bt_gatt_attr *attr, uint16_t value) { + LOG_DBG("value %d", value); +} +#endif /* ZMK_KEYMAP_HAS_SENSORS */ #if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) #include @@ -152,6 +173,7 @@ BT_GATT_SERVICE_DEFINE( #if ZMK_KEYMAP_HAS_SENSORS BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID), BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT, +<<<<<<< HEAD split_svc_sensor_state, NULL, &last_sensor_event), BT_GATT_CCC(split_svc_sensor_state_ccc, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), #endif /* ZMK_KEYMAP_HAS_SENSORS */ @@ -160,6 +182,11 @@ BT_GATT_SERVICE_DEFINE( BT_GATT_CHRC_WRITE_WITHOUT_RESP, BT_GATT_PERM_WRITE_ENCRYPT, NULL, split_svc_update_indicators, NULL), #endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) +======= + split_svc_sensor_state, NULL, &sensor_event), + BT_GATT_CCC(split_svc_sensor_state_ccc, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), +#endif /* ZMK_KEYMAP_HAS_SENSORS */ +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 ); K_THREAD_STACK_DEFINE(service_q_stack, CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE); @@ -214,6 +241,7 @@ int zmk_split_bt_position_released(uint8_t position) { } #if ZMK_KEYMAP_HAS_SENSORS +<<<<<<< HEAD K_MSGQ_DEFINE(sensor_state_msgq, sizeof(struct sensor_event), CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE, 4); @@ -221,6 +249,16 @@ void send_sensor_state_callback(struct k_work *work) { while (k_msgq_get(&sensor_state_msgq, &last_sensor_event, K_NO_WAIT) == 0) { int err = bt_gatt_notify(NULL, &split_svc.attrs[8], &last_sensor_event, sizeof(last_sensor_event)); +======= +K_MSGQ_DEFINE(sensor_state_msgq, sizeof(sensor_event), + CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE, 4); + +void send_sensor_state_callback(struct k_work *work) { + struct sensor_event ev; + + while (k_msgq_get(&sensor_state_msgq, &ev, K_NO_WAIT) == 0) { + int err = bt_gatt_notify(NULL, &split_svc.attrs[5], &ev, sizeof(ev)); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 if (err) { LOG_DBG("Error notifying %d", err); } @@ -229,8 +267,13 @@ void send_sensor_state_callback(struct k_work *work) { K_WORK_DEFINE(service_sensor_notify_work, send_sensor_state_callback); +<<<<<<< HEAD int send_sensor_state(struct sensor_event ev) { int err = k_msgq_put(&sensor_state_msgq, &ev, K_MSEC(100)); +======= +int send_sensor_state() { + int err = k_msgq_put(&sensor_state_msgq, &sensor_event, K_MSEC(100)); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 if (err) { // retry... switch (err) { @@ -238,7 +281,11 @@ int send_sensor_state(struct sensor_event ev) { LOG_WRN("Sensor state message queue full, popping first message and queueing again"); struct sensor_event discarded_state; k_msgq_get(&sensor_state_msgq, &discarded_state, K_NO_WAIT); +<<<<<<< HEAD return send_sensor_state(ev); +======= + return send_sensor_state(); +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } default: LOG_WRN("Failed to queue sensor state to send (%d)", err); @@ -250,6 +297,7 @@ int send_sensor_state(struct sensor_event ev) { return 0; } +<<<<<<< HEAD int zmk_split_bt_sensor_triggered(uint8_t sensor_index, const struct zmk_sensor_channel_data channel_data[], size_t channel_data_size) { @@ -266,6 +314,16 @@ int zmk_split_bt_sensor_triggered(uint8_t sensor_index, #endif /* ZMK_KEYMAP_HAS_SENSORS */ static int service_init(void) { +======= +int zmk_split_bt_sensor_triggered(uint8_t sensor_number, struct sensor_value value) { + sensor_event.sensor_number = sensor_number; + sensor_event.value = value; + return send_sensor_state(); +} +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + +int service_init(const struct device *_arg) { +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 static const struct k_work_queue_config queue_config = { .name = "Split Peripheral Notification Queue"}; k_work_queue_start(&service_work_q, service_q_stack, K_THREAD_STACK_SIZEOF(service_q_stack), diff --git a/app/src/split/bluetooth/split_listener.c b/app/src/split/bluetooth/split_listener.c index 9b680d2c89c..bdbd4387289 100644 --- a/app/src/split/bluetooth/split_listener.c +++ b/app/src/split/bluetooth/split_listener.c @@ -4,8 +4,14 @@ * SPDX-License-Identifier: MIT */ +<<<<<<< HEAD #include #include +======= +#include +#include +#include +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 #include @@ -22,18 +28,33 @@ int split_listener(const zmk_event_t *eh) { LOG_DBG(""); const struct zmk_position_state_changed *pos_ev; if ((pos_ev = as_zmk_position_state_changed(eh)) != NULL) { +<<<<<<< HEAD if (pos_ev->state) { return zmk_split_bt_position_pressed(pos_ev->position); } else { return zmk_split_bt_position_released(pos_ev->position); +======= + if (pos_ev != NULL) { + if (pos_ev->state) { + return zmk_split_bt_position_pressed(pos_ev->position); + } else { + return zmk_split_bt_position_released(pos_ev->position); + } +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } } #if ZMK_KEYMAP_HAS_SENSORS const struct zmk_sensor_event *sensor_ev; if ((sensor_ev = as_zmk_sensor_event(eh)) != NULL) { +<<<<<<< HEAD return zmk_split_bt_sensor_triggered(sensor_ev->sensor_index, sensor_ev->channel_data, sensor_ev->channel_data_size); +======= + if (sensor_ev != NULL) { + return zmk_split_bt_sensor_triggered(sensor_ev->sensor_number, sensor_ev->value); + } +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 } #endif /* ZMK_KEYMAP_HAS_SENSORS */ return ZMK_EV_EVENT_BUBBLE; diff --git a/app/tests/mouse-keys/mmv/events.patterns b/app/tests/mouse-keys/mmv/events.patterns new file mode 100644 index 00000000000..833100f6ac4 --- /dev/null +++ b/app/tests/mouse-keys/mmv/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/mouse-keys/mmv/keycode_events.snapshot b/app/tests/mouse-keys/mmv/keycode_events.snapshot new file mode 100644 index 00000000000..259501ba3d9 --- /dev/null +++ b/app/tests/mouse-keys/mmv/keycode_events.snapshot @@ -0,0 +1,2 @@ +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/mouse-keys/mmv/native_posix.keymap b/app/tests/mouse-keys/mmv/native_posix.keymap new file mode 100644 index 00000000000..ecf06601c05 --- /dev/null +++ b/app/tests/mouse-keys/mmv/native_posix.keymap @@ -0,0 +1,26 @@ +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &mmv MOVE_LEFT &none + &none &none + >; + }; + }; +}; + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/docs/docs/behaviors/mod-morph.md b/docs/docs/behaviors/mod-morph.md index 7ecb9ab8983..438042965e5 100644 --- a/docs/docs/behaviors/mod-morph.md +++ b/docs/docs/behaviors/mod-morph.md @@ -14,6 +14,15 @@ The Mod-Morph behavior sends a different keypress, depending on whether a specif The Mod-Morph behavior acts as one of two keycodes, depending on if the required modifier is being held during the keypress. +<<<<<<< HEAD +======= +When the modifier is being held it is sent along with the morphed keycode. This can cause problems when the morphed keycode and modifier have an existing relationship (such as `shift-delete` or `ctrl-v` on many operating systems). + +As a remedy, you can add the optional attribute `masked_mods`, containing +the bitwise OR of the modifiers that should be disabled while the key is held, +so that they are not included in the report sent to the host. + +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 ### Configuration An example of how to implement the mod-morph "Grave Escape": @@ -26,6 +35,7 @@ An example of how to implement the mod-morph "Grave Escape": #binding-cells = <0>; bindings = <&kp ESC>, <&kp GRAVE>; mods = <(MOD_LGUI|MOD_LSFT|MOD_RGUI|MOD_RSFT)>; + masked_mods = <(MOD_LGUI|MOD_LSFT)>; // don't send left modifiers }; }; }; diff --git a/docs/docs/behaviors/mouse-emulation.md b/docs/docs/behaviors/mouse-emulation.md index 9ed0dd8e07b..35e251e28db 100644 --- a/docs/docs/behaviors/mouse-emulation.md +++ b/docs/docs/behaviors/mouse-emulation.md @@ -5,6 +5,7 @@ sidebar_label: Mouse Emulation ## Summary +<<<<<<< HEAD Mouse emulation behaviors send mouse events. Currently, only mouse button presses are supported, but movement and scroll action support is planned for the future. @@ -13,16 +14,41 @@ Whenever the Mouse Emulation feature is turned on or off, the HID protocol used ## Configuration Option This feature can be enabled or disabled explicitly via a config option: +======= +Mouse emulation behaviors send mouse movements, button presses or scroll actions. + +Please view [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) for a comprehensive list of signals. + +## Configuration options + +This feature should be enabled via a config option: +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 ``` CONFIG_ZMK_MOUSE=y ``` +<<<<<<< HEAD If you use the mouse key press behavior in your keymap, the feature will automatically be enabled for you. ## Mouse Button Defines To make it easier to encode the HID mouse button numeric values, include +======= +This option enables several others. + +### Dedicated thread processing + +`CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED` is enabled by default and separates the processing of mouse signals into a dedicated thread, significantly improving performance. + +### Tick rate configuration + +`CONFIG_ZMK_MOUSE_TICK_DURATION` sets the tick rate for mouse polling. It is set to 8 ms. by default. + +## Keycode Defines + +To make it easier to encode the HID keycode numeric values, most keymaps include +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 the [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) header provided by ZMK near the top: @@ -30,13 +56,22 @@ provided by ZMK near the top: #include ``` +<<<<<<< HEAD ## Mouse Button Press This behavior can press/release up to 5 mouse buttons. +======= +Doing so allows using a set of defines such as `MOVE_UP`, `MOVE_DOWN`, `LCLK` and `SCROLL_UP` with these behaviors. + +## Mouse Button Press + +This behavior can press/release up to 16 mouse buttons. +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 ### Behavior Binding - Reference: `&mkp` +<<<<<<< HEAD - Parameter: A `uint8` with bits 0 through 4 each referring to a button. The following defines can be passed for the parameter: @@ -54,13 +89,74 @@ Mouse buttons 4 and 5 typically map to "back" and "forward" actions in most appl ### Examples The following will send a left click press when the binding is triggered: +======= +- Parameter: A `uint16` with each bit referring to a button. + +Example: +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 ``` &mkp LCLK ``` +<<<<<<< HEAD This example will send press of the fourth mouse button when the binding is triggered: ``` &mkp MB4 +======= +## Mouse Movement + +This behavior is used to manipulate the cursor. + +### Behavior Binding + +- Reference: `&mmv` +- Parameter: A `uint32` with the first 16 bits relating to horizontal movement + and the last 16 - to vertical movement. + +Example: + +``` +&mmv MOVE_UP +``` + +## Mouse Scrolling + +This behaviour is used to scroll, both horizontally and vertically. + +### Behavior Binding + +- Reference: `&mwh` +- Parameter: A `uint16` with the first 8 bits relating to horizontal movement + and the last 8 - to vertical movement. + +Example: + +``` +&mwh SCROLL_UP +``` + +## Acceleration + +Both mouse movement and scrolling have independently configurable acceleration profiles with three parameters: delay before movement, time to max speed and the acceleration exponent. +The exponent is usually set to 0 for constant speed, 1 for uniform acceleration or 2 for uniform jerk. + +These profiles can be configured inside your keymap: + +``` +&mmv { + time-to-max-speed-ms = <500>; +}; + +&mwh { + acceleration-exponent=<1>; +}; + +/ { + keymap { + ... + }; +}; +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 ``` diff --git a/docs/docs/features/slider.md b/docs/docs/features/slider.md new file mode 100644 index 00000000000..ad3e76fa99a --- /dev/null +++ b/docs/docs/features/slider.md @@ -0,0 +1,106 @@ +--- +title: Slider +sidebar_label: Slider +--- + +All devices which can generate 1-d continuous incremental position changes in one manueover +are classified as a slider. +Examples are capacitive touchbar, potentialmeter slider etc.. +Rotary encoder is not considered as slider, since the manueover generates an on/off state change +by nature. + +The implementation of the slider feature uses a capacitive slider as the reference design. +The slider is composed of multiple discrete capacitive sensors in a row. +These sensors can be used as buttons seperately or as a single slider cooperatively. +The implementation support three modes: +- button : only button usage is activated +- slider : only slider usage is activeated +- mix : both button and slider usages are activated + + +The reference hardware is based on [CAP1203](https://www.microchip.com/en-us/product/CAP1203), which supports up to three input sensors. +The driver of CAP1203 is basically a kscan device, with support of slide moanuover. +The device node is a I2C slave defined as: +``` + &i2c0 { + compatible = "nordic,nrf-twi"; + sda-pin = ; + scl-pin = ; + status = "okay"; + + kscan1: kscan1@28 { + compatible = "zmk,kscan-cap1203"; + status = "okay"; + reg = <0x28>; + int-gpios = <&gpio1 11 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + }; + }; +``` + +The different working mode is selected using Kconfig options: +- CONFIG_CAP1203_BUTTON_MODE +- CONFIG_CAP1203_SLIDER_MODE +- CONFIG_CAP1203_MIX_MODE + +## Button Mode +The driver node works as a normal kscan driver like others. +The keypress related behaviors are all supported naturally. +It can be set as the main chosen node by itself: +``` +chosen { + zmk,kscan = &kscan1; + zmk,matrix_transform = &default_transform; +}; +``` + +Or more likely, it can be a component of a composite kscan node: +``` +``` +To enable the driver code, the following configuration should also be added in config file: +``` +chosen { + zmk,kscan = &kscan; + zmk,matrix_transform = &default_transform; +}; + +kscan: kscan { + compatible = "zmk,kscan-composite"; + label = "KSCAN"; + rows = <2>; + columns = <7>; + + normal_keys { + kscan = <&kscan0>; + }; + + touch_keys: touch_keys { + kscan = <&kscan1>; + row-offset = <1>; + }; + }; + +kscan0: kscan0 { + compatible = "zmk,kscan-gpio-direct"; + label = "KEYBOARD-MATRIX"; + input-gpios + = <&gpio0 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpio0 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpio0 24 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpio0 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpio0 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpio1 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpio1 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + }; +``` + +## Slider Mode + +## Mix Mode + + +## Programming Interface +A dedicated data structure `slider_data` needs to be inserted at the beginning of the +device driver's data structure. +A kscan wrapper of the kscan api is used to hold a `kscan_slider_configure` function. +`kscan_slider_configure` is used to setup the slider callback and the slider id in the system. diff --git a/docs/docs/intro.md b/docs/docs/intro.md index da01e8297e7..5c0232f4b5a 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -33,7 +33,7 @@ ZMK is currently missing some features found in other popular firmware. This tab | One Shot Keys | ✅ | ✅ | ✅ | | [Combo Keys](features/combos.md) | ✅ | | ✅ | | [Macros](behaviors/macros.md) | ✅ | ✅ | ✅ | -| Mouse Keys | 🚧 | ✅ | ✅ | +| Mouse Keys | ✅ | ✅ | ✅ | | Low Active Power Usage | ✅ | | | | Low Power Sleep States | ✅ | ✅ | | | [Low Power Mode (VCC Shutoff)](behaviors/power.md) | ✅ | ✅ | | @@ -43,7 +43,13 @@ ZMK is currently missing some features found in other popular firmware. This tab | AVR/8 Bit | | | ✅ | | [Wide Range of ARM Chips Supported](https://docs.zephyrproject.org/3.5.0/boards/index.html) | ✅ | | | +<<<<<<< HEAD [^2]: Tap-Dances are limited to single and double-tap on BlueMicro +======= + +[^3]: Tap-Dances are limited to single and double-tap on BlueMicro +[^2]: Encoders are not currently supported on peripheral side splits. +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 [^1]: OLEDs are currently proof of concept in ZMK. ## Code Of Conduct diff --git a/docs/sidebars.js b/docs/sidebars.js index 284eb09b38e..e5ad30f7fd8 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -35,7 +35,10 @@ module.exports = { "behaviors/tap-dance", "behaviors/caps-word", "behaviors/key-repeat", +<<<<<<< HEAD "behaviors/sensor-rotate", +======= +>>>>>>> 5591ade36fef72969c7328b61dd0da901d713048 "behaviors/mouse-emulation", "behaviors/reset", "behaviors/bluetooth",