/*
 * Copyright (c) 2006-2022, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-04-04     tfx2001      first version
 */

#include <stdarg.h>
#include <stdint.h>
#include <math.h>

#include <rtthread.h>
#include <tusb.h>

#include "../usb_descriptor.h"

#define CIRCLE_RADIUS 300

static const uint8_t conv_table[128][2] =  { HID_ASCII_TO_KEYCODE };
static struct rt_semaphore hid_sem;

void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len)
{
    (void) instance;
    (void) report;
    (void) len;

    rt_sem_release(&hid_sem);
}

static void hid_press_key(uint8_t modifier, uint8_t keycode)
{
    uint8_t keycode_array[6] = {0};

    keycode_array[0] = keycode;
    tud_hid_keyboard_report(REPORT_ID_KEYBOARD, modifier, keycode_array);
    rt_sem_take(&hid_sem, 100);
    keycode_array[0] = 0;
    tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode_array);
    rt_sem_take(&hid_sem, 100);
}

static void hid_type_str_fmt(const char *fmt, ...)
{
    uint8_t  keycode;
    uint8_t  modifier;
    uint32_t length;
    va_list  args;
    char     buffer[64];
    char     chr;

    va_start(args, fmt);
    rt_vsnprintf(buffer, 64, fmt, args);

    length = rt_strlen(buffer);
    for (int i = 0; i < length; i++)
    {
        chr = buffer[i];
        if (conv_table[chr][0])
        {
            modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
        }
        else
        {
            modifier = 0;
        }
        keycode = conv_table[chr][1];
        hid_press_key(modifier, keycode);
    }
}

void hid_example(void)
{
    float last_x_pos = CIRCLE_RADIUS, x_pos;
    float last_y_pos = 0, y_pos;

    // Init semaphore
    rt_sem_init(&hid_sem, "hid", 0, RT_IPC_FLAG_PRIO);

    if (tud_connected())
    {
        // Make the mouse move like a circle
        for (int i = 0; i < 360; i++)
        {
            x_pos = cosf((float)i / 57.3F) * CIRCLE_RADIUS;
            y_pos = sinf((float)i / 57.3F) * CIRCLE_RADIUS;

            tud_hid_mouse_report(REPORT_ID_MOUSE, 0,
                                 (int8_t)(x_pos - last_x_pos), (int8_t)(y_pos - last_y_pos), 0, 0);
            rt_sem_take(&hid_sem, 100);

            last_x_pos = x_pos;
            last_y_pos = y_pos;
        }
        rt_thread_mdelay(500);

        // Open notepad and type something...
        hid_press_key(KEYBOARD_MODIFIER_LEFTGUI, HID_KEY_R);
        rt_thread_mdelay(500);
        hid_type_str_fmt("notepad\n\n");
        rt_thread_mdelay(2000);
        hid_type_str_fmt("This is RT-Thread TinyUSB demo.\n");
    }
    else
    {
        rt_kprintf("please connect USB port\n");
    }

    rt_sem_detach(&hid_sem);
}
MSH_CMD_EXPORT(hid_example, TinyUSB hid example)
