Alex Lisitsyn 2f0cb8b5f1 tinyusb: add support of esp32s3 target
add support of new esp32s3 target and the board
update the roles.mk wrapper to allow dfu flashing of espressif chip
update examples to allow compilation for esp32s3_addax_1 board
once the code is tested the PR to original tinyusb repo will be submitted
2021-04-16 13:38:00 +02:00

337 lines
9.0 KiB
C

/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", 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 THE
* AUTHORS OR COPYRIGHT HOLDERS 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 THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "queue.h"
#include "semphr.h"
#include "bsp/board.h"
#include "tusb.h"
#include "usb_descriptors.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
/* Blink pattern
* - 250 ms : device not mounted
* - 1000 ms : device mounted
* - 2500 ms : device is suspended
*/
enum {
BLINK_NOT_MOUNTED = 250,
BLINK_MOUNTED = 1000,
BLINK_SUSPENDED = 2500,
};
// static timer
StaticTimer_t blinky_tmdef;
TimerHandle_t blinky_tm;
// static task for usbd
#if CFG_TUSB_DEBUG
#define USBD_STACK_SIZE (3*configMINIMAL_STACK_SIZE)
#else
#define USBD_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2)
#endif
StackType_t usb_device_stack[USBD_STACK_SIZE];
StaticTask_t usb_device_taskdef;
// static task for hid
#define HID_STACK_SZIE configMINIMAL_STACK_SIZE
StackType_t hid_stack[HID_STACK_SZIE];
StaticTask_t hid_taskdef;
void led_blinky_cb(TimerHandle_t xTimer);
void usb_device_task(void* param);
void hid_task(void* params);
//--------------------------------------------------------------------+
// Main
//--------------------------------------------------------------------+
int main(void)
{
board_init();
// soft timer for blinky
blinky_tm = xTimerCreateStatic(NULL, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), true, NULL, led_blinky_cb, &blinky_tmdef);
xTimerStart(blinky_tm, 0);
// Create a task for tinyusb device stack
(void) xTaskCreateStatic( usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, usb_device_stack, &usb_device_taskdef);
// Create HID task
(void) xTaskCreateStatic( hid_task, "hid", HID_STACK_SZIE, NULL, configMAX_PRIORITIES-2, hid_stack, &hid_taskdef);
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
#if CFG_TUSB_MCU != OPT_MCU_ESP32S2 && CFG_TUSB_MCU != OPT_MCU_ESP32S3
vTaskStartScheduler();
#endif
return 0;
}
#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
void app_main(void)
{
main();
}
#endif
// USB Device Driver task
// This top level thread process all usb events and invoke callbacks
void usb_device_task(void* param)
{
(void) param;
// This should be called after scheduler/kernel is started.
// Otherwise it could cause kernel issue since USB IRQ handler does use RTOS queue API.
tusb_init();
// RTOS forever loop
while (1)
{
// tinyusb device task
tud_task();
}
}
//--------------------------------------------------------------------+
// Device callbacks
//--------------------------------------------------------------------+
// Invoked when device is mounted
void tud_mount_cb(void)
{
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
}
// Invoked when device is unmounted
void tud_umount_cb(void)
{
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), 0);
}
// Invoked when usb bus is suspended
// remote_wakeup_en : if host allow us to perform remote wakeup
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
void tud_suspend_cb(bool remote_wakeup_en)
{
(void) remote_wakeup_en;
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_SUSPENDED), 0);
}
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
}
//--------------------------------------------------------------------+
// USB HID
//--------------------------------------------------------------------+
static void send_hid_report(uint8_t report_id, uint32_t btn)
{
// skip if hid is not ready yet
if ( !tud_hid_ready() ) return;
switch(report_id)
{
case REPORT_ID_KEYBOARD:
{
// use to avoid send multiple consecutive zero report for keyboard
static bool has_keyboard_key = false;
if ( btn )
{
uint8_t keycode[6] = { 0 };
keycode[0] = HID_KEY_A;
tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode);
has_keyboard_key = true;
}else
{
// send empty key report if previously has key pressed
if (has_keyboard_key) tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL);
has_keyboard_key = false;
}
}
break;
case REPORT_ID_MOUSE:
{
int8_t const delta = 5;
// no button, right + down, no scroll, no pan
tud_hid_mouse_report(REPORT_ID_MOUSE, 0x00, delta, delta, 0, 0);
}
break;
case REPORT_ID_CONSUMER_CONTROL:
{
// use to avoid send multiple consecutive zero report
static bool has_consumer_key = false;
if ( btn )
{
// volume down
uint16_t volume_down = HID_USAGE_CONSUMER_VOLUME_DECREMENT;
tud_hid_report(REPORT_ID_CONSUMER_CONTROL, &volume_down, 2);
has_consumer_key = true;
}else
{
// send empty key report (release key) if previously has key pressed
uint16_t empty_key = 0;
if (has_consumer_key) tud_hid_report(REPORT_ID_CONSUMER_CONTROL, &empty_key, 2);
has_consumer_key = false;
}
}
break;
case REPORT_ID_GAMEPAD:
{
// use to avoid send multiple consecutive zero report for keyboard
static bool has_gamepad_key = false;
hid_gamepad_report_t report =
{
.x = 0, .y = 0, .z = 0, .rz = 0, .rx = 0, .ry = 0,
.hat = 0, .buttons = 0
};
if ( btn )
{
report.hat = GAMEPAD_HAT_UP;
report.buttons = GAMEPAD_BUTTON_A;
tud_hid_report(REPORT_ID_GAMEPAD, &report, sizeof(report));
has_gamepad_key = true;
}else
{
report.hat = GAMEPAD_HAT_CENTERED;
report.buttons = 0;
if (has_gamepad_key) tud_hid_report(REPORT_ID_GAMEPAD, &report, sizeof(report));
has_gamepad_key = false;
}
}
break;
default: break;
}
}
void hid_task(void* param)
{
(void) param;
while(1)
{
// Poll every 10ms
vTaskDelay(pdMS_TO_TICKS(10));
uint32_t const btn = board_button_read();
// Remote wakeup
if ( tud_suspended() && btn )
{
// Wake up host if we are in suspend mode
// and REMOTE_WAKEUP feature is enabled by host
tud_remote_wakeup();
}
else
{
// Send the 1st of report chain, the rest will be sent by tud_hid_report_complete_cb()
send_hid_report(REPORT_ID_KEYBOARD, btn);
}
}
}
// Invoked when sent REPORT successfully to host
// Application can use this to send the next report
// Note: For composite reports, report[0] is report ID
void tud_hid_report_complete_cb(uint8_t itf, uint8_t const* report, uint8_t len)
{
(void) itf;
(void) len;
uint8_t next_report_id = report[0] + 1;
if (next_report_id < REPORT_ID_COUNT)
{
send_hid_report(next_report_id, board_button_read());
}
}
// Invoked when received GET_REPORT control request
// Application must fill buffer report's content and return its length.
// Return zero will cause the stack to STALL request
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
{
// TODO not Implemented
(void) itf;
(void) report_id;
(void) report_type;
(void) buffer;
(void) reqlen;
return 0;
}
// Invoked when received SET_REPORT control request or
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
{
// TODO set LED based on CAPLOCK, NUMLOCK etc...
(void) itf;
(void) report_id;
(void) report_type;
(void) buffer;
(void) bufsize;
}
//--------------------------------------------------------------------+
// BLINKING TASK
//--------------------------------------------------------------------+
void led_blinky_cb(TimerHandle_t xTimer)
{
(void) xTimer;
static bool led_state = false;
board_led_write(led_state);
led_state = 1 - led_state; // toggle
}