blob: 6a297418b4cbb0b7174b7af19f2a41a26197130c [file] [log] [blame]
/*
* Copyright (c) 2018 qianfan Zhao
* Copyright (c) 2018, 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/input/input.h>
#include <zephyr/sys/util.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/usb/class/usb_hid.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
static const uint8_t hid_report_desc[] = HID_MOUSE_REPORT_DESC(2);
static enum usb_dc_status_code usb_status;
#define MOUSE_BTN_LEFT 0
#define MOUSE_BTN_RIGHT 1
enum mouse_report_idx {
MOUSE_BTN_REPORT_IDX = 0,
MOUSE_X_REPORT_IDX = 1,
MOUSE_Y_REPORT_IDX = 2,
MOUSE_WHEEL_REPORT_IDX = 3,
MOUSE_REPORT_COUNT = 4,
};
static uint8_t report[MOUSE_REPORT_COUNT];
static K_SEM_DEFINE(report_sem, 0, 1);
static void status_cb(enum usb_dc_status_code status, const uint8_t *param)
{
usb_status = status;
}
static ALWAYS_INLINE void rwup_if_suspended(void)
{
if (IS_ENABLED(CONFIG_USB_DEVICE_REMOTE_WAKEUP)) {
if (usb_status == USB_DC_SUSPEND) {
usb_wakeup_request();
return;
}
}
}
static void input_cb(struct input_event *evt)
{
uint8_t tmp[MOUSE_REPORT_COUNT];
(void)memcpy(tmp, report, sizeof(tmp));
switch (evt->code) {
case INPUT_KEY_0:
rwup_if_suspended();
WRITE_BIT(tmp[MOUSE_BTN_REPORT_IDX], MOUSE_BTN_LEFT, evt->value);
break;
case INPUT_KEY_1:
rwup_if_suspended();
WRITE_BIT(tmp[MOUSE_BTN_REPORT_IDX], MOUSE_BTN_RIGHT, evt->value);
break;
case INPUT_KEY_2:
if (evt->value) {
tmp[MOUSE_X_REPORT_IDX] += 10U;
}
break;
case INPUT_KEY_3:
if (evt->value) {
tmp[MOUSE_Y_REPORT_IDX] += 10U;
}
break;
default:
LOG_INF("Unrecognized input code %u value %d",
evt->code, evt->value);
return;
}
if (memcmp(tmp, report, sizeof(tmp))) {
memcpy(report, tmp, sizeof(report));
k_sem_give(&report_sem);
}
}
INPUT_CALLBACK_DEFINE(NULL, input_cb);
int main(void)
{
const struct device *hid_dev;
int ret;
if (!gpio_is_ready_dt(&led0)) {
LOG_ERR("LED device %s is not ready", led0.port->name);
return 0;
}
hid_dev = device_get_binding("HID_0");
if (hid_dev == NULL) {
LOG_ERR("Cannot get USB HID Device");
return 0;
}
ret = gpio_pin_configure_dt(&led0, GPIO_OUTPUT);
if (ret < 0) {
LOG_ERR("Failed to configure the LED pin, error: %d", ret);
return 0;
}
usb_hid_register_device(hid_dev,
hid_report_desc, sizeof(hid_report_desc),
NULL);
usb_hid_init(hid_dev);
ret = usb_enable(status_cb);
if (ret != 0) {
LOG_ERR("Failed to enable USB");
return 0;
}
while (true) {
k_sem_take(&report_sem, K_FOREVER);
ret = hid_int_ep_write(hid_dev, report, sizeof(report), NULL);
report[MOUSE_X_REPORT_IDX] = 0U;
report[MOUSE_Y_REPORT_IDX] = 0U;
if (ret) {
LOG_ERR("HID write error, %d", ret);
}
/* Toggle LED on sent report */
ret = gpio_pin_toggle(led0.port, led0.pin);
if (ret < 0) {
LOG_ERR("Failed to toggle the LED pin, error: %d", ret);
}
}
return 0;
}