From f681d7a19ab211e63bb837f43ce4269216187b3d Mon Sep 17 00:00:00 2001 From: Conor Patrick Date: Sat, 2 Jun 2018 00:20:04 -0400 Subject: [PATCH] add fix for engineering A errata and refactor --- nrf52840/Makefile | 1 + nrf52840/app_config.h | 4 +- nrf52840/main.c | 1415 ++--------------------------------------- nrf52840/usb.c | 1194 ++++++++++++++++++++++++++++++++++ nrf52840/usb.h | 6 + 5 files changed, 1246 insertions(+), 1374 deletions(-) create mode 100644 nrf52840/usb.c create mode 100644 nrf52840/usb.h diff --git a/nrf52840/Makefile b/nrf52840/Makefile index 4c14b79..81b0711 100644 --- a/nrf52840/Makefile +++ b/nrf52840/Makefile @@ -12,6 +12,7 @@ $(OUTPUT_DIRECTORY)/nrf52840_xxaa.out: \ SRC_FILES += \ $(SDK_ROOT)/modules/nrfx/mdk/gcc_startup_nrf52840.S \ $(PROJ_DIR)/main.c \ + $(PROJ_DIR)/usb.c \ $(SDK_ROOT)/components/boards/boards.c \ $(SDK_ROOT)/components/libraries/util/app_error.c \ $(SDK_ROOT)/components/libraries/util/app_error_handler_gcc.c \ diff --git a/nrf52840/app_config.h b/nrf52840/app_config.h index 738199c..ecba132 100644 --- a/nrf52840/app_config.h +++ b/nrf52840/app_config.h @@ -11,7 +11,7 @@ // SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS - Size of upstream buffer. #ifndef SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS -#define SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS 4 +#define SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS 8 #endif // SEGGER_RTT_CONFIG_BUFFER_SIZE_DOWN - Size of upstream buffer. @@ -21,7 +21,7 @@ // SEGGER_RTT_CONFIG_MAX_NUM_DOWN_BUFFERS - Size of upstream buffer. #ifndef SEGGER_RTT_CONFIG_MAX_NUM_DOWN_BUFFERS -#define SEGGER_RTT_CONFIG_MAX_NUM_DOWN_BUFFERS 4 +#define SEGGER_RTT_CONFIG_MAX_NUM_DOWN_BUFFERS 8 #endif // SEGGER_RTT_CONFIG_DEFAULT_MODE - RTT behavior if the buffer is full. diff --git a/nrf52840/main.c b/nrf52840/main.c index af0426c..43b82f3 100644 --- a/nrf52840/main.c +++ b/nrf52840/main.c @@ -50,17 +50,20 @@ #define DEBUG #include #include + #include "nrf.h" #include "nrf_gpio.h" #include "nrf_delay.h" -#include "boards.h" - +#include "nrf_drv_clock.h" +#include "nrf_drv_power.h" #include "nrf_strerror.h" - #include "nrf_drv_rtc.h" #include "nrf_drv_clock.h" #include "SEGGER_RTT.h" +#include "boards.h" + +#include "usb.h" #define COMPARE_COUNTERTIME (3UL) /**< Get Compare event COMPARE_TIME seconds after the counter starts from 0. */ @@ -92,18 +95,28 @@ void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) ; } +void log_resetreason(void); -/** @brief Function starting the internal LFCLK XTAL oscillator. - */ -static void lfclk_config(void) + +static void init_power_clock(void) { - ret_code_t err_code = nrf_drv_clock_init(); - APP_ERROR_CHECK(err_code); - + ret_code_t ret; + /* Initializing power and clock */ + ret = nrf_drv_clock_init(); + APP_ERROR_CHECK(ret); + ret = nrf_drv_power_init(NULL); + APP_ERROR_CHECK(ret); + nrf_drv_clock_hfclk_request(NULL); nrf_drv_clock_lfclk_request(NULL); + while (!(nrf_drv_clock_hfclk_is_running() && + nrf_drv_clock_lfclk_is_running())) + { + /* Just waiting */ + } } + static void rtc_config(void) { uint32_t err_code; @@ -125,19 +138,36 @@ static void rtc_config(void) nrf_drv_rtc_enable(&rtc); } -int usb_main(void); + + int main(void) { /* Configure board. */ /*bsp_board_init(BSP_INIT_LEDS);*/ /*lfclk_config();*/ - /*rtc_config();*/ /*SEGGER_RTT_printf(0, "Hello FIDO2\n");*/ uint32_t count; int i = 0; - - usb_main(); + + printf("hello FIDO2\r\n"); + log_resetreason(); + if ((nrf_power_resetreas_get() & NRF_POWER_RESETREAS_RESETPIN_MASK) == 0) + { + // Hard reset. this is for engineering A sample to work for USB ... + nrf_power_resetreas_clear(nrf_power_resetreas_get()); + nrf_gpio_cfg_output(NRF_GPIO_PIN_MAP(0,31)); + nrf_gpio_pin_clear(NRF_GPIO_PIN_MAP(0,31)); + while (1) + ; + } + nrf_power_resetreas_clear(nrf_power_resetreas_get()); + + + init_power_clock(); + rtc_config(); + usb_init(); + while (1) { i++; @@ -156,1363 +186,4 @@ int main(void) } } -/** - * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -#include -#include -#include -#include "nrf.h" -#include "nrf_drv_usbd.h" -#include "nrf_drv_clock.h" -#include "nrf_gpio.h" -#include "nrf_delay.h" -#include "nrf_drv_power.h" -#include "nrf_log.h" -#include "nrf_log_ctrl.h" -#include "nrf_log_default_backends.h" -#include "app_timer.h" -#include "app_error.h" -#include "bsp.h" -#include "bsp_cli.h" -#include "nrf_cli.h" -/*#include "nrf_cli_uart.h"*/ -/** - * @brief CLI interface over UART - */ -/*NRF_CLI_UART_DEF(m_cli_uart_transport, 0, 64, 16);*/ -/*NRF_CLI_DEF(m_cli_uart,*/ - /*"uart_cli:~$ ",*/ - /*&m_cli_uart_transport.transport,*/ - /*'\r',*/ - /*4);*/ - -static bool m_send_flag = 0; - -#define BTN_DATA_SEND 0 -#define BTN_DATA_KEY_RELEASE (bsp_event_t)(BSP_EVENT_KEY_LAST + 1) - -/** - * @brief Button used to simulate mouse move - * - * Every button press would move the cursor one step in the square. - */ -#define BTN_MOUSE_MOVE BSP_BOARD_BUTTON_0 -/** - * @brief Button for system OFF request - * - * This button would set the request for system OFF. - */ -#define BTN_SYSTEM_OFF BSP_BOARD_BUTTON_1 - -/** - * @brief Configuration status LED - * - * This LED would blink quickly (5 Hz) when device is not configured - * or slowly (1 Hz) when configured and working properly. - */ -#define LED_USB_STATUS BSP_BOARD_LED_0 -/** - * @brief Power detect LED - * - * The LED is ON when connection is detected on USB port. - * It is turned off when connection is removed. - */ -#define LED_USB_POWER BSP_BOARD_LED_1 - -/** - * @brief Running LED - * - * LED that turns on when program is not sleeping - */ -#define LED_RUNNING BSP_BOARD_LED_2 - -/** - * @brief Active LED - * - * LED that turns on when program is not in system OFF - */ -#define LED_ACTIVE BSP_BOARD_LED_3 - -/** - * @brief Enable power USB detection - * - * Configure if example supports USB port connection - */ -#ifndef USBD_POWER_DETECTION -#define USBD_POWER_DETECTION true -#endif - -/** - * @brief Startup delay - * - * Number of microseconds to start USBD after powering up. - * Kind of port insert debouncing. - */ -#define STARTUP_DELAY 100 - - -/** Maximum size of the packed transfered by EP0 */ -#define EP0_MAXPACKETSIZE NRF_DRV_USBD_EPSIZE - -/** Device descriptor */ -#define USBD_DEVICE_DESCRIPTOR \ - 0x12, /* bLength | size of descriptor */\ - 0x01, /* bDescriptorType | descriptor type */\ - 0x00, 0x02, /* bcdUSB | USB spec release (ver 2.0) */\ - 0x00, /* bDeviceClass ¦ class code (each interface specifies class information) */\ - 0x00, /* bDeviceSubClass ¦ device sub-class (must be set to 0 because class code is 0) */\ - 0x00, /* bDeviceProtocol | device protocol (no class specific protocol) */\ - EP0_MAXPACKETSIZE, /* bMaxPacketSize0 | maximum packet size (64 bytes) */\ - 0x15, 0x19, /* vendor ID (0x1915 Nordic) */\ - 0xAA, 0xAA, /* product ID (0x520A nRF52 HID mouse on nrf_drv) */\ - 0x05, 0x01, /* bcdDevice | final device release number in BCD Format */\ - USBD_STRING_MANUFACTURER_IX, /* iManufacturer | index of manufacturer string */\ - USBD_STRING_PRODUCT_IX, /* iProduct | index of product string */\ - USBD_STRING_SERIAL_IX, /* iSerialNumber | Serial Number string */\ - 0x01 /* bNumConfigurations | number of configurations */ - -/** Configuration descriptor */ -#define DEVICE_SELF_POWERED 0 -#define REMOTE_WU 1 - -#define USBD_CONFIG_DESCRIPTOR_SIZE 9 -#define USBD_CONFIG_DESCRIPTOR_FULL_SIZE (9 + (9 + 9 + 7 + 7)) -#define USBD_CONFIG_DESCRIPTOR \ - 0x09, /* bLength | length of descriptor */\ - 0x02, /* bDescriptorType | descriptor type (CONFIGURATION) */\ - USBD_CONFIG_DESCRIPTOR_FULL_SIZE, 0x00, /* wTotalLength | total length of descriptor(s) */\ - 0x01, /* bNumInterfaces */\ - 0x01, /* bConfigurationValue */\ - 0x00, /* index of string Configuration | configuration string index (not supported) */\ - 0x80| (((DEVICE_SELF_POWERED) ? 1U:0U)<<6) | (((REMOTE_WU) ? 1U:0U)<<5), /* bmAttributes */\ - 49 /* maximum power in steps of 2mA (98mA) */ - -#define USBD_INTERFACE0_DESCRIPTOR \ - 0x09, /* bLength */\ - 0x04, /* bDescriptorType | descriptor type (INTERFACE) */\ - 0x00, /* bInterfaceNumber */\ - 0x00, /* bAlternateSetting */\ - 0x02, /* bNumEndpoints | number of endpoints (1) */\ - 0x03, /* bInterfaceClass | interface class (3..defined by USB spec: HID) */\ - 0x00, /* bInterfaceSubClass |interface sub-class (0.. no boot interface) */\ - 0x00, /* bInterfaceProtocol | interface protocol (1..defined by USB spec: mouse) */\ - 0x00 /* interface string index (not supported) */ - -/** - * HID Table must normally be between Interface and EndPoint Descriptor - * as written in HID spec§7.1 but it doesn't work with OSR2.1 - */ -#define USBD_HID0_DESCRIPTOR \ - 0x09, /* bLength | length of descriptor (9 bytes) */\ - 0x21, /* bHIDDescriptor | descriptor type (HID) */\ - 0x11, 0x00, /* HID wBcdHID | Spec version 01.11 */\ - 0x00, /* bCountryCode | HW Target country */\ - 0x01, /* bNumDescriptors | Number of HID class descriptors to follow */\ - 0x22, /* bDescriptorType | Report descriptor type is 0x22 (report) */\ - (uint8_t)(USBD_MOUSE_REPORT_DESCRIPTOR_SIZE), /* Total length of Report descr., low byte */ \ - (uint8_t)(USBD_MOUSE_REPORT_DESCRIPTOR_SIZE / 256) /* Total length of Report descr., high byte */ - -#define USBD_ENDPOINT1_DESCRIPTOR \ - 0x07, /* bLength | length of descriptor (7 bytes) */\ - 0x05, /* bDescriptorType | descriptor type (ENDPOINT) */\ - 0x01, /* bEndpointAddress | endpoint address (IN endpoint, endpoint 1) */\ - 0x03, /* bmAttributes | endpoint attributes (interrupt) */\ - 0x40,0x00, /* bMaxPacketSizeLowByte,bMaxPacketSizeHighByte | maximum packet size (64 bytes) */\ - 0x08 /* bInterval | polling interval (10ms) */ - - -#define USBD_ENDPOINT2_DESCRIPTOR \ - 0x07, /* bLength | length of descriptor (7 bytes) */\ - 0x05, /* bDescriptorType | descriptor type (ENDPOINT) */\ - 0x81, /* bEndpointAddress | endpoint address (IN endpoint, endpoint 1) */\ - 0x03, /* bmAttributes | endpoint attributes (interrupt) */\ - 0x40,0x00, /* bMaxPacketSizeLowByte,bMaxPacketSizeHighByte | maximum packet size (64 bytes) */\ - 0x08 /* bInterval | polling interval (10ms) */ - - -/** - * String config descriptor - */ -#define USBD_STRING_LANG_IX 0x00 -#define USBD_STRING_LANG \ - 0x04, /* length of descriptor */\ - 0x03, /* descriptor type */\ - 0x09, /* */\ - 0x04 /* Supported LangID = 0x0409 (US-English) */ - -#define USBD_STRING_MANUFACTURER_IX 0x01 -#define USBD_STRING_MANUFACTURER \ - 16, /* length of descriptor (? bytes) */\ - 0x03, /* descriptor type */\ - 'N', 0x00, /* Define Unicode String "Nordic Semiconductor */\ - 'e', 0x00, \ - 'e', 0x00, \ - 'd', 0x00, \ - 'a', 0x00, \ - ' ', 0x00, \ - 'N', 0x00, - -#define USBD_STRING_PRODUCT_IX 0x02 -#define USBD_STRING_PRODUCT \ - 24, /* length of descriptor (? bytes) */\ - 0x03, /* descriptor type */\ - 'F', 0x00, /* generic unicode string for all devices */\ - 'I', 0x00, \ - 'D', 0x00, \ - 'O', 0x00, \ - '2', 0x00, \ - ' ', 0x00, \ - 'T', 0x00, \ - 'o', 0x00, \ - 'k', 0x00, \ - 'e', 0x00, \ - 'n', 0x00, \ - - -#define USBD_STRING_SERIAL_IX 0x00 - -#define USBD_MOUSE_REPORT_DESCRIPTOR_SIZE 34 -#define USBD_MOUSE_REPORT_DESCRIPTOR \ - 0x06, 0xd0, 0xf1,/* usage page (FIDO alliance). Global item */\ - 0x09, 0x01, /* usage (CTAPHID). Local item */\ - 0xA1, 0x01, /* collection (application) */\ - 0x09, 0x20, /* usage (FIDO_USAGE_DATA_IN) */\ - 0x15, 0x00, /* logical minimum (0) */\ - 0x26, 0xFF, 0x00,/* logical maximum (255) */\ - 0x75, 0x08, /* report size (8) */\ - 0x95, 0x40, /* report count (64) */\ - 0x81, 0x02, /* HID_Input (HID_Data | HID_Absolute | HID_Variable) */\ - 0x09, 0x21, /* usage (FIDO_USAGE_DATA_OUT) */\ - 0x15, 0x00, /* logical minimum (0) */\ - 0x26, 0xFF, 0x00,/* logical maximum (255) */\ - 0x75, 0x08, /* report size (8) */\ - 0x95, 0x40, /* report count (64) */\ - 0x91, 0x02, /* HID_Output (HID_Data | HID_Absolute | HID_Variable) */\ - 0xC0 /* End Collection */ - - -static const uint8_t get_descriptor_device[] = { - USBD_DEVICE_DESCRIPTOR -}; - -static const uint8_t get_descriptor_configuration[] = { - USBD_CONFIG_DESCRIPTOR, - USBD_INTERFACE0_DESCRIPTOR, - USBD_HID0_DESCRIPTOR, - USBD_ENDPOINT1_DESCRIPTOR, - USBD_ENDPOINT2_DESCRIPTOR -}; -static const uint8_t get_descriptor_string_lang[] = { - USBD_STRING_LANG -}; -static const uint8_t get_descriptor_string_manuf[] = { - USBD_STRING_MANUFACTURER -}; -static const uint8_t get_descriptor_string_prod[] = { - USBD_STRING_PRODUCT -}; -static const uint8_t get_descriptor_report_interface_0[] = { - USBD_MOUSE_REPORT_DESCRIPTOR -}; - -static const uint8_t get_config_resp_configured[] = {1}; -static const uint8_t get_config_resp_unconfigured[] = {0}; - -static const uint8_t get_status_device_resp_nrwu[] = { - ((DEVICE_SELF_POWERED) ? 1 : 0), //LSB first: self-powered, no remoteWk - 0 -}; -static const uint8_t get_status_device_resp_rwu[] = { - ((DEVICE_SELF_POWERED) ? 1 : 0) | 2, //LSB first: self-powered, remoteWk - 0 -}; - -static const uint8_t get_status_interface_resp[] = {0, 0}; -static const uint8_t get_status_ep_halted_resp[] = {1, 0}; -static const uint8_t get_status_ep_active_resp[] = {0, 0}; - - -#define GET_CONFIG_DESC_SIZE sizeof(get_descriptor_configuration) -#define GET_INTERFACE_DESC_SIZE 9 -#define GET_HID_DESC_SIZE 9 -#define GET_ENDPOINT_DESC_SIZE 7 - -#define get_descriptor_interface_0 \ - &get_descriptor_configuration[9] -#define get_descriptor_hid_0 \ - &get_descriptor_configuration[9+GET_INTERFACE_DESC_SIZE] -#define get_descriptor_endpoint_1 \ - &get_descriptor_configuration[9+GET_INTERFACE_DESC_SIZE+GET_HID_DESC_SIZE] -#define get_descriptor_endpoint_2 \ - &get_descriptor_configuration[9+GET_INTERFACE_DESC_SIZE+GET_HID_DESC_SIZE+7] - - -/** - * @brief USB configured flag - * - * The flag that is used to mark the fact that USB is configured and ready - * to transmit data - */ -static volatile bool m_usbd_configured = false; - -/** - * @brief USB suspended - * - * The flag that is used to mark the fact that USB is suspended and requires wake up - * if new data is available. - * - * @note This variable is changed from the main loop. - */ -static bool m_usbd_suspended = false; - -/** - * @brief Mark the fact if remote wake up is enabled - * - * The internal flag that marks if host enabled the remote wake up functionality in this device. - */ -static -#if REMOTE_WU - volatile // Disallow optimization only if Remote wakeup is enabled -#endif -bool m_usbd_rwu_enabled = false; - -/** - * @brief Current mouse position - * - * The index of current mouse position that would be changed to real offset. - */ -static volatile uint8_t m_mouse_position = 0; - -/** - * @brief The flag for mouse position send pending - * - * Setting this flag means that USB endpoint is busy by sending - * last mouse position. - */ -static volatile bool m_send_mouse_position = false; - -/** - * @brief The requested suspend state - * - * The currently requested suspend state based on the events - * received from USBD library. - * If the value here is different than the @ref m_usbd_suspended - * the state changing would be processed inside main loop. - */ -static volatile bool m_usbd_suspend_state_req = false; - -/** - * @brief System OFF request flag - * - * This flag is used in button event processing and marks the fact that - * system OFF should be activated from main loop. - */ -static volatile bool m_system_off_req = false; - - -/** - * @brief Setup all the endpoints for selected configuration - * - * Function sets all the endpoints for specific configuration. - * - * @note - * Setting the configuration index 0 means technically disabling the HID interface. - * Such configuration should be set when device is starting or USB reset is detected. - * - * @param index Configuration index - * - * @retval NRF_ERROR_INVALID_PARAM Invalid configuration - * @retval NRF_SUCCESS Configuration successfully set - */ -static ret_code_t ep_configuration(uint8_t index) -{ - if ( index == 1 ) - { - nrf_drv_usbd_ep_dtoggle_clear(NRF_DRV_USBD_EPIN1); - nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPIN1); - nrf_drv_usbd_ep_enable(NRF_DRV_USBD_EPIN1); - - nrf_drv_usbd_ep_dtoggle_clear(NRF_DRV_USBD_EPOUT1); - nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPOUT1); - nrf_drv_usbd_ep_enable(NRF_DRV_USBD_EPOUT1); - - m_usbd_configured = true; - nrf_drv_usbd_setup_clear(); - } - else if ( index == 0 ) - { - nrf_drv_usbd_ep_disable(NRF_DRV_USBD_EPIN1); - m_usbd_configured = false; - nrf_drv_usbd_setup_clear(); - } - else - { - return NRF_ERROR_INVALID_PARAM; - } - return NRF_SUCCESS; -} - -/** - * @name Processing setup requests - * - * @{ - */ -/** - * @brief Respond on ep 0 - * - * Auxiliary function for sending respond on endpoint 0 - * @param[in] p_setup Pointer to setup data from current setup request. - * It would be used to calculate the size of data to send. - * @param[in] p_data Pointer to the data to send. - * @param[in] size Number of bytes to send. - * @note Data pointed by p_data has to be available till the USBD_EVT_BUFREADY event. - */ -static void respond_setup_data( - nrf_drv_usbd_setup_t const * const p_setup, - void const * p_data, size_t size) -{ - /* Check the size against required response size */ - if (size > p_setup->wLength) - { - size = p_setup->wLength; - } - ret_code_t ret; - nrf_drv_usbd_transfer_t transfer = - { - .p_data = {.tx = p_data}, - .size = size - }; - ret = nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPIN0, &transfer); - if (ret != NRF_SUCCESS) - { - printf("Transfer starting failed: %d", (uint32_t)ret); - } - ASSERT(ret == NRF_SUCCESS); - UNUSED_VARIABLE(ret); -} - - -/** React to GetStatus */ -static void usbd_setup_GetStatus(nrf_drv_usbd_setup_t const * const p_setup) -{ - switch (p_setup->bmRequestType) - { - case 0x80: // Device - if (((p_setup->wIndex) & 0xff) == 0) - { - respond_setup_data( - p_setup, - m_usbd_rwu_enabled ? get_status_device_resp_rwu : get_status_device_resp_nrwu, - sizeof(get_status_device_resp_nrwu)); - return; - } - break; - case 0x81: // Interface - if (m_usbd_configured) // Respond only if configured - { - if (((p_setup->wIndex) & 0xff) == 0) // Only interface 0 supported - { - respond_setup_data( - p_setup, - get_status_interface_resp, - sizeof(get_status_interface_resp)); - return; - } - } - break; - case 0x82: // Endpoint - if (((p_setup->wIndex) & 0xff) == 0) // Endpoint 0 - { - respond_setup_data( - p_setup, - get_status_ep_active_resp, - sizeof(get_status_ep_active_resp)); - return; - } - if (m_usbd_configured) // Other endpoints responds if configured - { - if (((p_setup->wIndex) & 0xff) == NRF_DRV_USBD_EPIN1) - { - if (nrf_drv_usbd_ep_stall_check(NRF_DRV_USBD_EPIN1)) - { - respond_setup_data( - p_setup, - get_status_ep_halted_resp, - sizeof(get_status_ep_halted_resp)); - return; - } - else - { - respond_setup_data( - p_setup, - get_status_ep_active_resp, - sizeof(get_status_ep_active_resp)); - return; - } - } - if (((p_setup->wIndex) & 0xff) == NRF_DRV_USBD_EPOUT1) - { - if (nrf_drv_usbd_ep_stall_check(NRF_DRV_USBD_EPOUT1)) - { - respond_setup_data( - p_setup, - get_status_ep_halted_resp, - sizeof(get_status_ep_halted_resp)); - return; - } - else - { - respond_setup_data( - p_setup, - get_status_ep_active_resp, - sizeof(get_status_ep_active_resp)); - return; - } - } - - } - break; - default: - break; // Just go to stall - } - printf("Unknown status: 0x%2x", p_setup->bmRequestType); - nrf_drv_usbd_setup_stall(); -} - -static void usbd_setup_ClearFeature(nrf_drv_usbd_setup_t const * const p_setup) -{ - if ((p_setup->bmRequestType) == 0x02) // standard request, recipient=endpoint - { - if ((p_setup->wValue) == 0) - { - if ((p_setup->wIndex) == NRF_DRV_USBD_EPIN1) - { - nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPIN1); - nrf_drv_usbd_setup_clear(); - return; - } - } - } - else if ((p_setup->bmRequestType) == 0x0) // standard request, recipient=device - { - if (REMOTE_WU) - { - if ((p_setup->wValue) == 1) // Feature Wakeup - { - m_usbd_rwu_enabled = false; - nrf_drv_usbd_setup_clear(); - return; - } - } - } - printf("Unknown feature to clear"); - nrf_drv_usbd_setup_stall(); -} - -static void usbd_setup_SetFeature(nrf_drv_usbd_setup_t const * const p_setup) -{ - if ((p_setup->bmRequestType) == 0x02) // standard request, recipient=endpoint - { - if ((p_setup->wValue) == 0) // Feature HALT - { - if ((p_setup->wIndex) == NRF_DRV_USBD_EPIN1) - { - nrf_drv_usbd_ep_stall(NRF_DRV_USBD_EPIN1); - nrf_drv_usbd_setup_clear(); - return; - } - } - } - else if ((p_setup->bmRequestType) == 0x0) // standard request, recipient=device - { - if (REMOTE_WU) - { - if ((p_setup->wValue) == 1) // Feature Wakeup - { - m_usbd_rwu_enabled = true; - nrf_drv_usbd_setup_clear(); - return; - } - } - } - printf("Unknown feature to set"); - nrf_drv_usbd_setup_stall(); -} - -static void usbd_setup_GetDescriptor(nrf_drv_usbd_setup_t const * const p_setup) -{ - //determine which descriptor has been asked for - switch ((p_setup->wValue) >> 8) - { - case 1: // Device - if ((p_setup->bmRequestType) == 0x80) - { - respond_setup_data( - p_setup, - get_descriptor_device, - sizeof(get_descriptor_device)); - return; - } - break; - case 2: // Configuration - if ((p_setup->bmRequestType) == 0x80) - { - respond_setup_data( - p_setup, - get_descriptor_configuration, - GET_CONFIG_DESC_SIZE); - return; - } - break; - case 3: // String - if ((p_setup->bmRequestType) == 0x80) - { - // Select the string - switch ((p_setup->wValue) & 0xFF) - { - case USBD_STRING_LANG_IX: - respond_setup_data( - p_setup, - get_descriptor_string_lang, - sizeof(get_descriptor_string_lang)); - return; - case USBD_STRING_MANUFACTURER_IX: - respond_setup_data( - p_setup, - get_descriptor_string_manuf, - sizeof(get_descriptor_string_manuf)); - return; - case USBD_STRING_PRODUCT_IX: - respond_setup_data(p_setup, - get_descriptor_string_prod, - sizeof(get_descriptor_string_prod)); - return; - default: - break; - } - } - break; - case 4: // Interface - if ((p_setup->bmRequestType) == 0x80) - { - // Which interface? - if ((((p_setup->wValue) & 0xFF) == 0)) - { - respond_setup_data( - p_setup, - get_descriptor_interface_0, - GET_INTERFACE_DESC_SIZE); - return; - } - } - break; - case 5: // Endpoint - if ((p_setup->bmRequestType) == 0x80) - { - // Which endpoint? - printf("endpoint descriptor: %d\n", ((p_setup->wValue) & 0xFF)); - if (((p_setup->wValue) & 0xFF) == 1) - { - respond_setup_data( - p_setup, - get_descriptor_endpoint_1, - GET_ENDPOINT_DESC_SIZE); - return; - } - // Which endpoint? - if (((p_setup->wValue) & 0xFF) == 2) - { - respond_setup_data( - p_setup, - get_descriptor_endpoint_2, - GET_ENDPOINT_DESC_SIZE); - return; - } - } - break; - case 0x21: // HID - if ((p_setup->bmRequestType) == 0x81) - { - // Which interface - if (((p_setup->wValue) & 0xFF) == 0) - { - respond_setup_data( - p_setup, - get_descriptor_hid_0, - GET_HID_DESC_SIZE); - return; - } - } - break; - case 0x22: // HID report - if ((p_setup->bmRequestType) == 0x81) - { - // Which interface? - if (((p_setup->wValue) & 0xFF) == 0) - { - respond_setup_data( - p_setup, - get_descriptor_report_interface_0, - sizeof(get_descriptor_report_interface_0)); - return; - } - } - break; - default: - break; // Not supported - go to stall - } - - printf("Unknown : 0x%02x, type: 0x%02x or value: 0x%02x\n", - p_setup->wValue >> 8, - p_setup->bmRequestType, - p_setup->wValue & 0xFF); - nrf_drv_usbd_setup_stall(); -} - -static void usbd_setup_GetConfig(nrf_drv_usbd_setup_t const * const p_setup) -{ - if (m_usbd_configured) - { - respond_setup_data( - p_setup, - get_config_resp_configured, - sizeof(get_config_resp_configured)); - } - else - { - respond_setup_data( - p_setup, - get_config_resp_unconfigured, - sizeof(get_config_resp_unconfigured)); - } -} - -static void usbd_setup_SetConfig(nrf_drv_usbd_setup_t const * const p_setup) -{ - if ((p_setup->bmRequestType) == 0x00) - { - // accept only 0 and 1 - if (((p_setup->wIndex) == 0) && ((p_setup->wLength) == 0) && - ((p_setup->wValue) <= UINT8_MAX)) - { - if (NRF_SUCCESS == ep_configuration((uint8_t)(p_setup->wValue))) - { - nrf_drv_usbd_setup_clear(); - return; - } - } - } - printf("Wrong configuration: Index: 0x%2x, Value: 0x%2x.", - p_setup->wIndex, - p_setup->wValue); - nrf_drv_usbd_setup_stall(); -} - -static void usbd_setup_SetIdle(nrf_drv_usbd_setup_t const * const p_setup) -{ - if (p_setup->bmRequestType == 0x21) - { - //accept any value - nrf_drv_usbd_setup_clear(); - return; - } - printf("Set Idle wrong type: 0x%2x.", p_setup->bmRequestType); - nrf_drv_usbd_setup_stall(); -} - -static void usbd_setup_SetInterface( - nrf_drv_usbd_setup_t const * const p_setup) -{ - //no alternate setting is supported - STALL always - printf("No alternate interfaces supported."); - nrf_drv_usbd_setup_stall(); -} - -static void usbd_setup_SetProtocol( - nrf_drv_usbd_setup_t const * const p_setup) -{ - if (p_setup->bmRequestType == 0x21) - { - //accept any value - nrf_drv_usbd_setup_clear(); - return; - } - printf("Set Protocol wrong type: 0x%2x.", p_setup->bmRequestType); - nrf_drv_usbd_setup_stall(); -} - -/** @} */ /* End of processing setup requests functions */ - -void dump_hex(uint8_t * buf, int size) -{ - while(size--) - { - printf("%02x ", *buf++); - } - printf("\n"); -} - - - -static void usbd_event_handler(nrf_drv_usbd_evt_t const * const p_event) -{ - static uint8_t buf[64]; - nrf_drv_usbd_transfer_t transfer; - memset(&transfer, 0, sizeof(nrf_drv_usbd_transfer_t)); - - switch (p_event->type) - { - case NRF_DRV_USBD_EVT_SUSPEND: - printf("SUSPEND state detected\n"); - m_usbd_suspend_state_req = true; - break; - case NRF_DRV_USBD_EVT_RESUME: - printf("RESUMING from suspend\n"); - m_usbd_suspend_state_req = false; - break; - case NRF_DRV_USBD_EVT_WUREQ: - printf("RemoteWU initiated\n"); - m_usbd_suspend_state_req = false; - break; - case NRF_DRV_USBD_EVT_RESET: - { - ret_code_t ret = ep_configuration(0); - ASSERT(ret == NRF_SUCCESS); - UNUSED_VARIABLE(ret); - m_usbd_suspend_state_req = false; - break; - } - case NRF_DRV_USBD_EVT_SOF: - { - static uint32_t cycle = 0; - ++cycle; - if ((cycle % (m_usbd_configured ? 500 : 100)) == 0) - { - bsp_board_led_invert(LED_USB_STATUS); - } - break; - } - case NRF_DRV_USBD_EVT_EPTRANSFER: - if (NRF_DRV_USBD_EPOUT1 == p_event->data.eptransfer.ep) - { - switch(p_event->data.eptransfer.status) - { - case NRF_USBD_EP_OK: - /*printf("NRF_USBD_EP_OK\n");*/ - printf(">> ");dump_hex(buf,64); - break; - case NRF_USBD_EP_WAITING: - /*printf("NRF_USBD_EP_WAITING\n");*/ - transfer.p_data.rx = buf; - transfer.size = nrf_drv_usbd_epout_size_get(NRF_DRV_USBD_EPOUT1);; - if (transfer.size > 64) - { - printf("Error, invalid transfer size\n"); - return; - } - nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPOUT1, &transfer); - break; - case NRF_USBD_EP_OVERLOAD: - printf("NRF_USBD_EP_OVERLOAD\n"); - break; - case NRF_USBD_EP_ABORTED: - printf("NRF_USBD_EP_ABORTED\n"); - break; - default: - break; - } - - } - else if (NRF_DRV_USBD_EPIN0 == p_event->data.eptransfer.ep) - { - if (NRF_USBD_EP_OK == p_event->data.eptransfer.status) - { - if (!nrf_drv_usbd_errata_154()) - { - /* Transfer ok - allow status stage */ - nrf_drv_usbd_setup_clear(); - } - } - else if (NRF_USBD_EP_ABORTED == p_event->data.eptransfer.status) - { - /* Just ignore */ - printf("Transfer aborted event on EPIN0\n"); - } - else - { - printf("Transfer failed on EPIN0: %d", p_event->data.eptransfer.status); - nrf_drv_usbd_setup_stall(); - } - } - else if (NRF_DRV_USBD_EPOUT0 == p_event->data.eptransfer.ep) - { - /* NOTE: No EPOUT0 data transfers are used. - * The code is here as a pattern how to support such a transfer. */ - if (NRF_USBD_EP_OK == p_event->data.eptransfer.status) - { - /* NOTE: Data values or size may be tested here to decide if clear or stall. - * If errata 154 is present the data transfer is acknowledged by the hardware. */ - if (!nrf_drv_usbd_errata_154()) - { - /* Transfer ok - allow status stage */ - nrf_drv_usbd_setup_clear(); - } - } - else if (NRF_USBD_EP_ABORTED == p_event->data.eptransfer.status) - { - /* Just ignore */ - printf("Transfer aborted event on EPOUT0\n"); - } - else - { - printf("Transfer failed on EPOUT0: %d", p_event->data.eptransfer.status); - nrf_drv_usbd_setup_stall(); - } - } - else - { - printf("EP other: %d\n", p_event->data.eptransfer.ep); - /* Nothing to do */ - } - break; - case NRF_DRV_USBD_EVT_SETUP: - { - nrf_drv_usbd_setup_t setup; - nrf_drv_usbd_setup_get(&setup); - switch (setup.bmRequest) - { - case 0x00: // GetStatus - usbd_setup_GetStatus(&setup); - break; - case 0x01: // CleartFeature - usbd_setup_ClearFeature(&setup); - break; - case 0x03: // SetFeature - usbd_setup_SetFeature(&setup); - break; - case 0x05: // SetAddress - //nothing to do, handled by hardware; but don't STALL - break; - case 0x06: // GetDescriptor - usbd_setup_GetDescriptor(&setup); - break; - case 0x08: // GetConfig - usbd_setup_GetConfig(&setup); - break; - case 0x09: // SetConfig - usbd_setup_SetConfig(&setup); - break; - //HID class - case 0x0A: // SetIdle - usbd_setup_SetIdle(&setup); - break; - case 0x0B: // SetProtocol or SetInterface - if (setup.bmRequestType == 0x01) // standard request, recipient=interface - { - usbd_setup_SetInterface(&setup); - } - else if (setup.bmRequestType == 0x21) // class request, recipient=interface - { - usbd_setup_SetProtocol(&setup); - } - else - { - printf("Command 0xB. Unknown request: 0x%2x", setup.bmRequestType); - nrf_drv_usbd_setup_stall(); - } - break; - default: - printf("Unknown request: 0x%2x", setup.bmRequest); - nrf_drv_usbd_setup_stall(); - return; - } - break; - } - default: - printf("unknown usb event\n"); - break; - } -} - - -static void move_mouse_pointer(void) -{ - static uint32_t databuffer; - - if (!m_usbd_configured) - return; - if (!m_send_mouse_position) - { - switch (m_mouse_position & 0x3) - { - case 0: - /* X = 10, rest all are unchanged */ - databuffer = 0x00000A00; - break; - case 1: - /* Y = 10, rest all are unchanged */ - databuffer = 0x000A0000; - break; - case 2: - /* X = -10, rest all are unchanged */ - databuffer = 0x0000F600; - break; - case 3: - /* Y = -10, rest all are unchanged */ - databuffer = 0x00F60000; - break; - } - m_mouse_position++; - - /* Send data */ - static const nrf_drv_usbd_transfer_t transfer = - { - .p_data = {.tx = &databuffer}, - .size = sizeof(databuffer) - }; - m_send_mouse_position = true; - UNUSED_RETURN_VALUE(nrf_drv_usbd_ep_transfer( - NRF_DRV_USBD_EPIN1, - &transfer)); - } -} - -static void power_usb_event_handler(nrf_drv_power_usb_evt_t event) -{ - switch (event) - { - case NRF_DRV_POWER_USB_EVT_DETECTED: - printf("USB power detected\n"); - if (!nrf_drv_usbd_is_enabled()) - { - nrf_drv_usbd_enable(); - } - break; - case NRF_DRV_POWER_USB_EVT_REMOVED: - printf("USB power removed\n"); - m_usbd_configured = false; - m_send_mouse_position = false; - if (nrf_drv_usbd_is_started()) - { - nrf_drv_usbd_stop(); - } - if (nrf_drv_usbd_is_enabled()) - { - nrf_drv_usbd_disable(); - } - /* Turn OFF LEDs */ - bsp_board_led_off(LED_USB_STATUS); - bsp_board_led_off(LED_USB_POWER); - break; - case NRF_DRV_POWER_USB_EVT_READY: - printf("USB ready\n"); - bsp_board_led_on(LED_USB_POWER); - if (!nrf_drv_usbd_is_started()) - { - nrf_drv_usbd_start(true); - } - break; - default: - ASSERT(false); - } -} - -static void bsp_evt_handler(bsp_event_t evt) -{ - switch ((unsigned int)evt) - { - case BSP_EVENT_SYSOFF: - { - m_system_off_req = true; - break; - } - case CONCAT_2(BSP_EVENT_KEY_, BTN_DATA_SEND): - { - m_send_flag = 1; - break; - } - - case BTN_DATA_KEY_RELEASE: - { - m_send_flag = 0; - break; - } - default: - return; - } -} - -static void init_power_clock(void) -{ - ret_code_t ret; - /* Initializing power and clock */ - ret = nrf_drv_clock_init(); - APP_ERROR_CHECK(ret); - ret = nrf_drv_power_init(NULL); - APP_ERROR_CHECK(ret); - nrf_drv_clock_hfclk_request(NULL); - nrf_drv_clock_lfclk_request(NULL); - while (!(nrf_drv_clock_hfclk_is_running() && - nrf_drv_clock_lfclk_is_running())) - { - /* Just waiting */ - } - - ret = app_timer_init(); - APP_ERROR_CHECK(ret); - - /* Avoid warnings if assertion is disabled */ - UNUSED_VARIABLE(ret); -} - -static void init_bsp(void) -{ - ret_code_t ret; - ret = bsp_init(BSP_INIT_BUTTONS, bsp_evt_handler); - APP_ERROR_CHECK(ret); - - ret = bsp_event_to_button_action_assign( - BTN_SYSTEM_OFF, - BSP_BUTTON_ACTION_RELEASE, - BSP_EVENT_SYSOFF); - APP_ERROR_CHECK(ret); - ret = bsp_event_to_button_action_assign(BTN_DATA_SEND, - BSP_BUTTON_ACTION_RELEASE, - BTN_DATA_KEY_RELEASE); - APP_ERROR_CHECK(ret); - /* Avoid warnings if assertion is disabled */ - UNUSED_VARIABLE(ret); -} - -static void init_cli(void) -{ - ret_code_t ret; - ret = bsp_cli_init(bsp_evt_handler); - APP_ERROR_CHECK(ret); - /*nrf_drv_uart_config_t uart_config = NRF_DRV_UART_DEFAULT_CONFIG;*/ - /*uart_config.pseltxd = TX_PIN_NUMBER;*/ - /*uart_config.pselrxd = RX_PIN_NUMBER;*/ - /*uart_config.hwfc = NRF_UART_HWFC_DISABLED;*/ - /*ret = nrf_cli_init(&m_cli_uart, &uart_config, true, true, NRF_LOG_SEVERITY_INFO);*/ - /*APP_ERROR_CHECK(ret);*/ - /*ret = nrf_cli_start(&m_cli_uart);*/ - /*APP_ERROR_CHECK(ret);*/ -} - -static void log_resetreason(void) -{ - /* Reset reason */ - uint32_t rr = nrf_power_resetreas_get(); - printf("Reset reasons:\n"); - if (0 == rr) - { - printf("- NONE\n"); - } - if (0 != (rr & NRF_POWER_RESETREAS_RESETPIN_MASK)) - { - printf("- RESETPIN\n"); - } - if (0 != (rr & NRF_POWER_RESETREAS_DOG_MASK )) - { - printf("- DOG\n"); - } - if (0 != (rr & NRF_POWER_RESETREAS_SREQ_MASK )) - { - printf("- SREQ\n"); - } - if (0 != (rr & NRF_POWER_RESETREAS_LOCKUP_MASK )) - { - printf("- LOCKUP\n"); - } - if (0 != (rr & NRF_POWER_RESETREAS_OFF_MASK )) - { - printf("- OFF\n"); - } - if (0 != (rr & NRF_POWER_RESETREAS_LPCOMP_MASK )) - { - printf("- LPCOMP\n"); - } - if (0 != (rr & NRF_POWER_RESETREAS_DIF_MASK )) - { - printf("- DIF\n"); - } - if (0 != (rr & NRF_POWER_RESETREAS_NFC_MASK )) - { - printf("- NFC\n"); - } - if (0 != (rr & NRF_POWER_RESETREAS_VBUS_MASK )) - { - printf("- VBUS\n"); - } -} - -int usb_main(void) -{ - ret_code_t ret; - UNUSED_RETURN_VALUE(NRF_LOG_INIT(NULL)); - - init_power_clock(); - init_bsp(); - init_cli(); - - printf("USDB example started.\n"); - if (NRF_DRV_USBD_ERRATA_ENABLE) - { - printf("USB errata 104 %s\n", (uint32_t)(nrf_drv_usbd_errata_104() ? "enabled" : "disabled")); - printf("USB errata 154 %s\n", (uint32_t)(nrf_drv_usbd_errata_154() ? "enabled" : "disabled")); - } - log_resetreason(); - nrf_power_resetreas_clear(nrf_power_resetreas_get()); - - /* USB work starts right here */ - ret = nrf_drv_usbd_init(usbd_event_handler); - APP_ERROR_CHECK(ret); - - /* Configure selected size of the packed on EP0 */ - nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPOUT0, EP0_MAXPACKETSIZE); - nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPIN0, EP0_MAXPACKETSIZE); - nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPOUT1, EP0_MAXPACKETSIZE); - nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPIN1, EP0_MAXPACKETSIZE); - - /* Configure LED and button */ - bsp_board_init(BSP_INIT_LEDS); - bsp_board_led_on(LED_RUNNING); - bsp_board_led_on(LED_ACTIVE); - - - if (USBD_POWER_DETECTION) - { - static const nrf_drv_power_usbevt_config_t config = - { - .handler = power_usb_event_handler - }; - ret = nrf_drv_power_usbevt_init(&config); - APP_ERROR_CHECK(ret); - } - else - { - printf("No USB power detection enabled\r\nStarting USB now\n"); - nrf_delay_us(STARTUP_DELAY); - if (!nrf_drv_usbd_is_enabled()) - { - nrf_drv_usbd_enable(); - ret = ep_configuration(0); - APP_ERROR_CHECK(ret); - } - /* Wait for regulator power up */ - while (NRF_DRV_POWER_USB_STATE_CONNECTED - == - nrf_drv_power_usbstatus_get()) - { - /* Just waiting */ - } - - if (NRF_DRV_POWER_USB_STATE_READY == nrf_drv_power_usbstatus_get()) - { - if (!nrf_drv_usbd_is_started()) - { - nrf_drv_usbd_start(true); - } - } - else - { - nrf_drv_usbd_disable(); - } - } - - - while (true) - { - if (m_system_off_req) - { - printf("Going to system OFF\n"); - NRF_LOG_FLUSH(); - bsp_board_led_off(LED_RUNNING); - bsp_board_led_off(LED_ACTIVE); - nrf_power_system_off(); - } - if (m_usbd_suspended != m_usbd_suspend_state_req) - { - if (m_usbd_suspend_state_req) - { - m_usbd_suspended = nrf_drv_usbd_suspend(); - if (m_usbd_suspended) - { - bsp_board_leds_off(); - } - } - else - { - m_usbd_suspended = false; - } - } - - if (m_usbd_configured) - { - if (m_send_flag) - { - if (m_usbd_suspended) - { - if (m_usbd_rwu_enabled) - { - UNUSED_RETURN_VALUE(nrf_drv_usbd_wakeup_req()); - } - } - else - { - printf(" TX pointer\n"); - move_mouse_pointer(); - } - } - } - - /*nrf_cli_process(&m_cli_uart);*/ - UNUSED_RETURN_VALUE(NRF_LOG_PROCESS()); - bsp_board_led_off(LED_RUNNING); - /* Even if we miss an event enabling USB, - * USB event would wake us up. */ - __WFE(); - /* Clear SEV flag if CPU was woken up by event */ - __SEV(); - __WFE(); - bsp_board_led_on(LED_RUNNING); - } -} diff --git a/nrf52840/usb.c b/nrf52840/usb.c new file mode 100644 index 0000000..ad2e349 --- /dev/null +++ b/nrf52840/usb.c @@ -0,0 +1,1194 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include "nrf.h" +#include "nrf_drv_usbd.h" +#include "nrf_drv_clock.h" +#include "nrf_gpio.h" +#include "nrf_delay.h" +#include "nrf_drv_power.h" +#include "nrf_log.h" +#include "nrf_log_ctrl.h" +#include "nrf_log_default_backends.h" +#include "app_timer.h" +#include "app_error.h" +#include "bsp.h" +#include "bsp_cli.h" +#include "nrf_cli.h" + +#include "SEGGER_RTT.h" +#define printf(fmt,...) SEGGER_RTT_printf(0, fmt, ##__VA_ARGS__); + +#define BTN_DATA_SEND 0 +#define BTN_DATA_KEY_RELEASE (bsp_event_t)(BSP_EVENT_KEY_LAST + 1) + +/** + * @brief Button used to simulate mouse move + * + * Every button press would move the cursor one step in the square. + */ +#define BTN_MOUSE_MOVE BSP_BOARD_BUTTON_0 +/** + * @brief Button for system OFF request + * + * This button would set the request for system OFF. + */ +#define BTN_SYSTEM_OFF BSP_BOARD_BUTTON_1 + +/** + * @brief Configuration status LED + * + * This LED would blink quickly (5 Hz) when device is not configured + * or slowly (1 Hz) when configured and working properly. + */ +#define LED_USB_STATUS BSP_BOARD_LED_0 +/** + * @brief Power detect LED + * + * The LED is ON when connection is detected on USB port. + * It is turned off when connection is removed. + */ +#define LED_USB_POWER BSP_BOARD_LED_1 + +/** + * @brief Running LED + * + * LED that turns on when program is not sleeping + */ +#define LED_RUNNING BSP_BOARD_LED_2 + +/** + * @brief Active LED + * + * LED that turns on when program is not in system OFF + */ +#define LED_ACTIVE BSP_BOARD_LED_3 + +/** + * @brief Enable power USB detection + * + * Configure if example supports USB port connection + */ +#ifndef USBD_POWER_DETECTION +#define USBD_POWER_DETECTION false +#endif + +/** + * @brief Startup delay + * + * Number of microseconds to start USBD after powering up. + * Kind of port insert debouncing. + */ +#define STARTUP_DELAY 100 + + +/** Maximum size of the packed transfered by EP0 */ +#define EP0_MAXPACKETSIZE NRF_DRV_USBD_EPSIZE + +/** Device descriptor */ +#define USBD_DEVICE_DESCRIPTOR \ + 0x12, /* bLength | size of descriptor */\ + 0x01, /* bDescriptorType | descriptor type */\ + 0x00, 0x02, /* bcdUSB | USB spec release (ver 2.0) */\ + 0x00, /* bDeviceClass ¦ class code (each interface specifies class information) */\ + 0x00, /* bDeviceSubClass ¦ device sub-class (must be set to 0 because class code is 0) */\ + 0x00, /* bDeviceProtocol | device protocol (no class specific protocol) */\ + EP0_MAXPACKETSIZE, /* bMaxPacketSize0 | maximum packet size (64 bytes) */\ + 0x15, 0x19, /* vendor ID (0x1915 Nordic) */\ + 0xAA, 0xAA, /* product ID (0x520A nRF52 HID mouse on nrf_drv) */\ + 0x05, 0x01, /* bcdDevice | final device release number in BCD Format */\ + USBD_STRING_MANUFACTURER_IX, /* iManufacturer | index of manufacturer string */\ + USBD_STRING_PRODUCT_IX, /* iProduct | index of product string */\ + USBD_STRING_SERIAL_IX, /* iSerialNumber | Serial Number string */\ + 0x01 /* bNumConfigurations | number of configurations */ + +/** Configuration descriptor */ +#define DEVICE_SELF_POWERED 0 +#define REMOTE_WU 1 + +#define USBD_CONFIG_DESCRIPTOR_SIZE 9 +#define USBD_CONFIG_DESCRIPTOR_FULL_SIZE (9 + (9 + 9 + 7 + 7)) +#define USBD_CONFIG_DESCRIPTOR \ + 0x09, /* bLength | length of descriptor */\ + 0x02, /* bDescriptorType | descriptor type (CONFIGURATION) */\ + USBD_CONFIG_DESCRIPTOR_FULL_SIZE, 0x00, /* wTotalLength | total length of descriptor(s) */\ + 0x01, /* bNumInterfaces */\ + 0x01, /* bConfigurationValue */\ + 0x00, /* index of string Configuration | configuration string index (not supported) */\ + 0x80| (((DEVICE_SELF_POWERED) ? 1U:0U)<<6) | (((REMOTE_WU) ? 1U:0U)<<5), /* bmAttributes */\ + 49 /* maximum power in steps of 2mA (98mA) */ + +#define USBD_INTERFACE0_DESCRIPTOR \ + 0x09, /* bLength */\ + 0x04, /* bDescriptorType | descriptor type (INTERFACE) */\ + 0x00, /* bInterfaceNumber */\ + 0x00, /* bAlternateSetting */\ + 0x02, /* bNumEndpoints | number of endpoints (1) */\ + 0x03, /* bInterfaceClass | interface class (3..defined by USB spec: HID) */\ + 0x00, /* bInterfaceSubClass |interface sub-class (0.. no boot interface) */\ + 0x00, /* bInterfaceProtocol | interface protocol (1..defined by USB spec: mouse) */\ + 0x00 /* interface string index (not supported) */ + +/** + * HID Table must normally be between Interface and EndPoint Descriptor + * as written in HID spec§7.1 but it doesn't work with OSR2.1 + */ +#define USBD_HID0_DESCRIPTOR \ + 0x09, /* bLength | length of descriptor (9 bytes) */\ + 0x21, /* bHIDDescriptor | descriptor type (HID) */\ + 0x11, 0x00, /* HID wBcdHID | Spec version 01.11 */\ + 0x00, /* bCountryCode | HW Target country */\ + 0x01, /* bNumDescriptors | Number of HID class descriptors to follow */\ + 0x22, /* bDescriptorType | Report descriptor type is 0x22 (report) */\ + (uint8_t)(USBD_MOUSE_REPORT_DESCRIPTOR_SIZE), /* Total length of Report descr., low byte */ \ + (uint8_t)(USBD_MOUSE_REPORT_DESCRIPTOR_SIZE / 256) /* Total length of Report descr., high byte */ + +#define USBD_ENDPOINT1_DESCRIPTOR \ + 0x07, /* bLength | length of descriptor (7 bytes) */\ + 0x05, /* bDescriptorType | descriptor type (ENDPOINT) */\ + 0x01, /* bEndpointAddress | endpoint address (IN endpoint, endpoint 1) */\ + 0x03, /* bmAttributes | endpoint attributes (interrupt) */\ + 0x40,0x00, /* bMaxPacketSizeLowByte,bMaxPacketSizeHighByte | maximum packet size (64 bytes) */\ + 0x08 /* bInterval | polling interval (10ms) */ + + +#define USBD_ENDPOINT2_DESCRIPTOR \ + 0x07, /* bLength | length of descriptor (7 bytes) */\ + 0x05, /* bDescriptorType | descriptor type (ENDPOINT) */\ + 0x81, /* bEndpointAddress | endpoint address (IN endpoint, endpoint 1) */\ + 0x03, /* bmAttributes | endpoint attributes (interrupt) */\ + 0x40,0x00, /* bMaxPacketSizeLowByte,bMaxPacketSizeHighByte | maximum packet size (64 bytes) */\ + 0x08 /* bInterval | polling interval (10ms) */ + + +/** + * String config descriptor + */ +#define USBD_STRING_LANG_IX 0x00 +#define USBD_STRING_LANG \ + 0x04, /* length of descriptor */\ + 0x03, /* descriptor type */\ + 0x09, /* */\ + 0x04 /* Supported LangID = 0x0409 (US-English) */ + +#define USBD_STRING_MANUFACTURER_IX 0x01 +#define USBD_STRING_MANUFACTURER \ + 16, /* length of descriptor (? bytes) */\ + 0x03, /* descriptor type */\ + 'N', 0x00, /* Define Unicode String "Nordic Semiconductor */\ + 'e', 0x00, \ + 'e', 0x00, \ + 'd', 0x00, \ + 'a', 0x00, \ + ' ', 0x00, \ + 'N', 0x00, + +#define USBD_STRING_PRODUCT_IX 0x02 +#define USBD_STRING_PRODUCT \ + 24, /* length of descriptor (? bytes) */\ + 0x03, /* descriptor type */\ + 'F', 0x00, /* generic unicode string for all devices */\ + 'I', 0x00, \ + 'D', 0x00, \ + 'O', 0x00, \ + '2', 0x00, \ + ' ', 0x00, \ + 'T', 0x00, \ + 'o', 0x00, \ + 'k', 0x00, \ + 'e', 0x00, \ + 'n', 0x00, \ + + +#define USBD_STRING_SERIAL_IX 0x00 + +#define USBD_MOUSE_REPORT_DESCRIPTOR_SIZE 34 +#define USBD_MOUSE_REPORT_DESCRIPTOR \ + 0x06, 0xd0, 0xf1,/* usage page (FIDO alliance). Global item */\ + 0x09, 0x01, /* usage (CTAPHID). Local item */\ + 0xA1, 0x01, /* collection (application) */\ + 0x09, 0x20, /* usage (FIDO_USAGE_DATA_IN) */\ + 0x15, 0x00, /* logical minimum (0) */\ + 0x26, 0xFF, 0x00,/* logical maximum (255) */\ + 0x75, 0x08, /* report size (8) */\ + 0x95, 0x40, /* report count (64) */\ + 0x81, 0x02, /* HID_Input (HID_Data | HID_Absolute | HID_Variable) */\ + 0x09, 0x21, /* usage (FIDO_USAGE_DATA_OUT) */\ + 0x15, 0x00, /* logical minimum (0) */\ + 0x26, 0xFF, 0x00,/* logical maximum (255) */\ + 0x75, 0x08, /* report size (8) */\ + 0x95, 0x40, /* report count (64) */\ + 0x91, 0x02, /* HID_Output (HID_Data | HID_Absolute | HID_Variable) */\ + 0xC0 /* End Collection */ + + +static const uint8_t get_descriptor_device[] = { + USBD_DEVICE_DESCRIPTOR +}; + +static const uint8_t get_descriptor_configuration[] = { + USBD_CONFIG_DESCRIPTOR, + USBD_INTERFACE0_DESCRIPTOR, + USBD_HID0_DESCRIPTOR, + USBD_ENDPOINT1_DESCRIPTOR, + USBD_ENDPOINT2_DESCRIPTOR +}; +static const uint8_t get_descriptor_string_lang[] = { + USBD_STRING_LANG +}; +static const uint8_t get_descriptor_string_manuf[] = { + USBD_STRING_MANUFACTURER +}; +static const uint8_t get_descriptor_string_prod[] = { + USBD_STRING_PRODUCT +}; +static const uint8_t get_descriptor_report_interface_0[] = { + USBD_MOUSE_REPORT_DESCRIPTOR +}; + +static const uint8_t get_config_resp_configured[] = {1}; +static const uint8_t get_config_resp_unconfigured[] = {0}; + +static const uint8_t get_status_device_resp_nrwu[] = { + ((DEVICE_SELF_POWERED) ? 1 : 0), //LSB first: self-powered, no remoteWk + 0 +}; +static const uint8_t get_status_device_resp_rwu[] = { + ((DEVICE_SELF_POWERED) ? 1 : 0) | 2, //LSB first: self-powered, remoteWk + 0 +}; + +static const uint8_t get_status_interface_resp[] = {0, 0}; +static const uint8_t get_status_ep_halted_resp[] = {1, 0}; +static const uint8_t get_status_ep_active_resp[] = {0, 0}; + + +#define GET_CONFIG_DESC_SIZE sizeof(get_descriptor_configuration) +#define GET_INTERFACE_DESC_SIZE 9 +#define GET_HID_DESC_SIZE 9 +#define GET_ENDPOINT_DESC_SIZE 7 + +#define get_descriptor_interface_0 \ + &get_descriptor_configuration[9] +#define get_descriptor_hid_0 \ + &get_descriptor_configuration[9+GET_INTERFACE_DESC_SIZE] +#define get_descriptor_endpoint_1 \ + &get_descriptor_configuration[9+GET_INTERFACE_DESC_SIZE+GET_HID_DESC_SIZE] +#define get_descriptor_endpoint_2 \ + &get_descriptor_configuration[9+GET_INTERFACE_DESC_SIZE+GET_HID_DESC_SIZE+7] + + +/** + * @brief USB configured flag + * + * The flag that is used to mark the fact that USB is configured and ready + * to transmit data + */ +static volatile bool m_usbd_configured = false; + + +/** + * @brief Mark the fact if remote wake up is enabled + * + * The internal flag that marks if host enabled the remote wake up functionality in this device. + */ +static +#if REMOTE_WU + volatile // Disallow optimization only if Remote wakeup is enabled +#endif +bool m_usbd_rwu_enabled = false; + +/** + * @brief Current mouse position + * + * The index of current mouse position that would be changed to real offset. + */ +static volatile uint8_t m_mouse_position = 0; + +/** + * @brief The flag for mouse position send pending + * + * Setting this flag means that USB endpoint is busy by sending + * last mouse position. + */ +static volatile bool m_send_mouse_position = false; + +/** + * @brief The requested suspend state + * + * The currently requested suspend state based on the events + * received from USBD library. + * If the value here is different than the @ref m_usbd_suspended + * the state changing would be processed inside main loop. + */ +static volatile bool m_usbd_suspend_state_req = false; + +/** + * @brief System OFF request flag + * + * This flag is used in button event processing and marks the fact that + * system OFF should be activated from main loop. + */ +static volatile bool m_system_off_req = false; + + +/** + * @brief Setup all the endpoints for selected configuration + * + * Function sets all the endpoints for specific configuration. + * + * @note + * Setting the configuration index 0 means technically disabling the HID interface. + * Such configuration should be set when device is starting or USB reset is detected. + * + * @param index Configuration index + * + * @retval NRF_ERROR_INVALID_PARAM Invalid configuration + * @retval NRF_SUCCESS Configuration successfully set + */ +static ret_code_t ep_configuration(uint8_t index) +{ + if ( index == 1 ) + { + nrf_drv_usbd_ep_dtoggle_clear(NRF_DRV_USBD_EPIN1); + nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPIN1); + nrf_drv_usbd_ep_enable(NRF_DRV_USBD_EPIN1); + + nrf_drv_usbd_ep_dtoggle_clear(NRF_DRV_USBD_EPOUT1); + nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPOUT1); + nrf_drv_usbd_ep_enable(NRF_DRV_USBD_EPOUT1); + + m_usbd_configured = true; + nrf_drv_usbd_setup_clear(); + } + else if ( index == 0 ) + { + nrf_drv_usbd_ep_disable(NRF_DRV_USBD_EPIN1); + m_usbd_configured = false; + nrf_drv_usbd_setup_clear(); + } + else + { + return NRF_ERROR_INVALID_PARAM; + } + return NRF_SUCCESS; +} + +/** + * @name Processing setup requests + * + * @{ + */ +/** + * @brief Respond on ep 0 + * + * Auxiliary function for sending respond on endpoint 0 + * @param[in] p_setup Pointer to setup data from current setup request. + * It would be used to calculate the size of data to send. + * @param[in] p_data Pointer to the data to send. + * @param[in] size Number of bytes to send. + * @note Data pointed by p_data has to be available till the USBD_EVT_BUFREADY event. + */ +static void respond_setup_data( + nrf_drv_usbd_setup_t const * const p_setup, + void const * p_data, size_t size) +{ + /* Check the size against required response size */ + if (size > p_setup->wLength) + { + size = p_setup->wLength; + } + ret_code_t ret; + nrf_drv_usbd_transfer_t transfer = + { + .p_data = {.tx = p_data}, + .size = size + }; + ret = nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPIN0, &transfer); + if (ret != NRF_SUCCESS) + { + printf("Transfer starting failed: %lu", (uint32_t)ret); + } + ASSERT(ret == NRF_SUCCESS); + UNUSED_VARIABLE(ret); +} + + +/** React to GetStatus */ +static void usbd_setup_GetStatus(nrf_drv_usbd_setup_t const * const p_setup) +{ + switch (p_setup->bmRequestType) + { + case 0x80: // Device + if (((p_setup->wIndex) & 0xff) == 0) + { + respond_setup_data( + p_setup, + m_usbd_rwu_enabled ? get_status_device_resp_rwu : get_status_device_resp_nrwu, + sizeof(get_status_device_resp_nrwu)); + return; + } + break; + case 0x81: // Interface + if (m_usbd_configured) // Respond only if configured + { + if (((p_setup->wIndex) & 0xff) == 0) // Only interface 0 supported + { + respond_setup_data( + p_setup, + get_status_interface_resp, + sizeof(get_status_interface_resp)); + return; + } + } + break; + case 0x82: // Endpoint + if (((p_setup->wIndex) & 0xff) == 0) // Endpoint 0 + { + respond_setup_data( + p_setup, + get_status_ep_active_resp, + sizeof(get_status_ep_active_resp)); + return; + } + if (m_usbd_configured) // Other endpoints responds if configured + { + if (((p_setup->wIndex) & 0xff) == NRF_DRV_USBD_EPIN1) + { + if (nrf_drv_usbd_ep_stall_check(NRF_DRV_USBD_EPIN1)) + { + respond_setup_data( + p_setup, + get_status_ep_halted_resp, + sizeof(get_status_ep_halted_resp)); + return; + } + else + { + respond_setup_data( + p_setup, + get_status_ep_active_resp, + sizeof(get_status_ep_active_resp)); + return; + } + } + if (((p_setup->wIndex) & 0xff) == NRF_DRV_USBD_EPOUT1) + { + if (nrf_drv_usbd_ep_stall_check(NRF_DRV_USBD_EPOUT1)) + { + respond_setup_data( + p_setup, + get_status_ep_halted_resp, + sizeof(get_status_ep_halted_resp)); + return; + } + else + { + respond_setup_data( + p_setup, + get_status_ep_active_resp, + sizeof(get_status_ep_active_resp)); + return; + } + } + + } + break; + default: + break; // Just go to stall + } + printf("Unknown status: 0x%2x", p_setup->bmRequestType); + nrf_drv_usbd_setup_stall(); +} + +static void usbd_setup_ClearFeature(nrf_drv_usbd_setup_t const * const p_setup) +{ + if ((p_setup->bmRequestType) == 0x02) // standard request, recipient=endpoint + { + if ((p_setup->wValue) == 0) + { + if ((p_setup->wIndex) == NRF_DRV_USBD_EPIN1) + { + nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPIN1); + nrf_drv_usbd_setup_clear(); + return; + } + } + } + else if ((p_setup->bmRequestType) == 0x0) // standard request, recipient=device + { + if (REMOTE_WU) + { + if ((p_setup->wValue) == 1) // Feature Wakeup + { + m_usbd_rwu_enabled = false; + nrf_drv_usbd_setup_clear(); + return; + } + } + } + printf("Unknown feature to clear"); + nrf_drv_usbd_setup_stall(); +} + +static void usbd_setup_SetFeature(nrf_drv_usbd_setup_t const * const p_setup) +{ + if ((p_setup->bmRequestType) == 0x02) // standard request, recipient=endpoint + { + if ((p_setup->wValue) == 0) // Feature HALT + { + if ((p_setup->wIndex) == NRF_DRV_USBD_EPIN1) + { + nrf_drv_usbd_ep_stall(NRF_DRV_USBD_EPIN1); + nrf_drv_usbd_setup_clear(); + return; + } + } + } + else if ((p_setup->bmRequestType) == 0x0) // standard request, recipient=device + { + if (REMOTE_WU) + { + if ((p_setup->wValue) == 1) // Feature Wakeup + { + m_usbd_rwu_enabled = true; + nrf_drv_usbd_setup_clear(); + return; + } + } + } + printf("Unknown feature to set"); + nrf_drv_usbd_setup_stall(); +} + +static void usbd_setup_GetDescriptor(nrf_drv_usbd_setup_t const * const p_setup) +{ + //determine which descriptor has been asked for + switch ((p_setup->wValue) >> 8) + { + case 1: // Device + if ((p_setup->bmRequestType) == 0x80) + { + respond_setup_data( + p_setup, + get_descriptor_device, + sizeof(get_descriptor_device)); + return; + } + break; + case 2: // Configuration + if ((p_setup->bmRequestType) == 0x80) + { + respond_setup_data( + p_setup, + get_descriptor_configuration, + GET_CONFIG_DESC_SIZE); + return; + } + break; + case 3: // String + if ((p_setup->bmRequestType) == 0x80) + { + // Select the string + switch ((p_setup->wValue) & 0xFF) + { + case USBD_STRING_LANG_IX: + respond_setup_data( + p_setup, + get_descriptor_string_lang, + sizeof(get_descriptor_string_lang)); + return; + case USBD_STRING_MANUFACTURER_IX: + respond_setup_data( + p_setup, + get_descriptor_string_manuf, + sizeof(get_descriptor_string_manuf)); + return; + case USBD_STRING_PRODUCT_IX: + respond_setup_data(p_setup, + get_descriptor_string_prod, + sizeof(get_descriptor_string_prod)); + return; + default: + break; + } + } + break; + case 4: // Interface + if ((p_setup->bmRequestType) == 0x80) + { + // Which interface? + if ((((p_setup->wValue) & 0xFF) == 0)) + { + respond_setup_data( + p_setup, + get_descriptor_interface_0, + GET_INTERFACE_DESC_SIZE); + return; + } + } + break; + case 5: // Endpoint + if ((p_setup->bmRequestType) == 0x80) + { + // Which endpoint? + printf("endpoint descriptor: %d\n", ((p_setup->wValue) & 0xFF)); + if (((p_setup->wValue) & 0xFF) == 1) + { + respond_setup_data( + p_setup, + get_descriptor_endpoint_1, + GET_ENDPOINT_DESC_SIZE); + return; + } + // Which endpoint? + if (((p_setup->wValue) & 0xFF) == 2) + { + respond_setup_data( + p_setup, + get_descriptor_endpoint_2, + GET_ENDPOINT_DESC_SIZE); + return; + } + } + break; + case 0x21: // HID + if ((p_setup->bmRequestType) == 0x81) + { + // Which interface + if (((p_setup->wValue) & 0xFF) == 0) + { + respond_setup_data( + p_setup, + get_descriptor_hid_0, + GET_HID_DESC_SIZE); + return; + } + } + break; + case 0x22: // HID report + if ((p_setup->bmRequestType) == 0x81) + { + // Which interface? + if (((p_setup->wValue) & 0xFF) == 0) + { + respond_setup_data( + p_setup, + get_descriptor_report_interface_0, + sizeof(get_descriptor_report_interface_0)); + return; + } + } + break; + default: + break; // Not supported - go to stall + } + + printf("Unknown : 0x%02x, type: 0x%02x or value: 0x%02x\n", + p_setup->wValue >> 8, + p_setup->bmRequestType, + p_setup->wValue & 0xFF); + nrf_drv_usbd_setup_stall(); +} + +static void usbd_setup_GetConfig(nrf_drv_usbd_setup_t const * const p_setup) +{ + if (m_usbd_configured) + { + respond_setup_data( + p_setup, + get_config_resp_configured, + sizeof(get_config_resp_configured)); + } + else + { + respond_setup_data( + p_setup, + get_config_resp_unconfigured, + sizeof(get_config_resp_unconfigured)); + } +} + +static void usbd_setup_SetConfig(nrf_drv_usbd_setup_t const * const p_setup) +{ + if ((p_setup->bmRequestType) == 0x00) + { + // accept only 0 and 1 + if (((p_setup->wIndex) == 0) && ((p_setup->wLength) == 0) && + ((p_setup->wValue) <= UINT8_MAX)) + { + if (NRF_SUCCESS == ep_configuration((uint8_t)(p_setup->wValue))) + { + nrf_drv_usbd_setup_clear(); + return; + } + } + } + printf("Wrong configuration: Index: 0x%2x, Value: 0x%2x.", + p_setup->wIndex, + p_setup->wValue); + nrf_drv_usbd_setup_stall(); +} + +static void usbd_setup_SetIdle(nrf_drv_usbd_setup_t const * const p_setup) +{ + if (p_setup->bmRequestType == 0x21) + { + //accept any value + nrf_drv_usbd_setup_clear(); + return; + } + printf("Set Idle wrong type: 0x%2x.", p_setup->bmRequestType); + nrf_drv_usbd_setup_stall(); +} + +static void usbd_setup_SetInterface( + nrf_drv_usbd_setup_t const * const p_setup) +{ + //no alternate setting is supported - STALL always + printf("No alternate interfaces supported."); + nrf_drv_usbd_setup_stall(); +} + +static void usbd_setup_SetProtocol( + nrf_drv_usbd_setup_t const * const p_setup) +{ + if (p_setup->bmRequestType == 0x21) + { + //accept any value + nrf_drv_usbd_setup_clear(); + return; + } + printf("Set Protocol wrong type: 0x%2x.", p_setup->bmRequestType); + nrf_drv_usbd_setup_stall(); +} + +/** @} */ /* End of processing setup requests functions */ + +void dump_hex(uint8_t * buf, int size) +{ + while(size--) + { + printf("%02x ", *buf++); + } + printf("\n"); +} + + + +static void usbd_event_handler(nrf_drv_usbd_evt_t const * const p_event) +{ + static uint8_t buf[64]; + nrf_drv_usbd_transfer_t transfer; + memset(&transfer, 0, sizeof(nrf_drv_usbd_transfer_t)); + + switch (p_event->type) + { + case NRF_DRV_USBD_EVT_SUSPEND: + printf("SUSPEND state detected\n"); + m_usbd_suspend_state_req = true; + break; + case NRF_DRV_USBD_EVT_RESUME: + printf("RESUMING from suspend\n"); + m_usbd_suspend_state_req = false; + break; + case NRF_DRV_USBD_EVT_WUREQ: + printf("RemoteWU initiated\n"); + m_usbd_suspend_state_req = false; + break; + case NRF_DRV_USBD_EVT_RESET: + { + ret_code_t ret = ep_configuration(0); + ASSERT(ret == NRF_SUCCESS); + UNUSED_VARIABLE(ret); + m_usbd_suspend_state_req = false; + break; + } + case NRF_DRV_USBD_EVT_SOF: + { + static uint32_t cycle = 0; + ++cycle; + if ((cycle % (m_usbd_configured ? 500 : 100)) == 0) + { + bsp_board_led_invert(LED_USB_STATUS); + } + break; + } + case NRF_DRV_USBD_EVT_EPTRANSFER: + if (NRF_DRV_USBD_EPOUT1 == p_event->data.eptransfer.ep) + { + switch(p_event->data.eptransfer.status) + { + case NRF_USBD_EP_OK: + /*printf("NRF_USBD_EP_OK\n");*/ + printf(">> ");dump_hex(buf,64); + break; + case NRF_USBD_EP_WAITING: + /*printf("NRF_USBD_EP_WAITING\n");*/ + transfer.p_data.rx = buf; + transfer.size = nrf_drv_usbd_epout_size_get(NRF_DRV_USBD_EPOUT1);; + if (transfer.size > 64) + { + printf("Error, invalid transfer size\n"); + return; + } + nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPOUT1, &transfer); + break; + case NRF_USBD_EP_OVERLOAD: + printf("NRF_USBD_EP_OVERLOAD\n"); + break; + case NRF_USBD_EP_ABORTED: + printf("NRF_USBD_EP_ABORTED\n"); + break; + default: + break; + } + + } + else if (NRF_DRV_USBD_EPIN0 == p_event->data.eptransfer.ep) + { + if (NRF_USBD_EP_OK == p_event->data.eptransfer.status) + { + if (!nrf_drv_usbd_errata_154()) + { + /* Transfer ok - allow status stage */ + nrf_drv_usbd_setup_clear(); + } + } + else if (NRF_USBD_EP_ABORTED == p_event->data.eptransfer.status) + { + /* Just ignore */ + printf("Transfer aborted event on EPIN0\n"); + } + else + { + printf("Transfer failed on EPIN0: %d", p_event->data.eptransfer.status); + nrf_drv_usbd_setup_stall(); + } + } + else if (NRF_DRV_USBD_EPOUT0 == p_event->data.eptransfer.ep) + { + /* NOTE: No EPOUT0 data transfers are used. + * The code is here as a pattern how to support such a transfer. */ + if (NRF_USBD_EP_OK == p_event->data.eptransfer.status) + { + /* NOTE: Data values or size may be tested here to decide if clear or stall. + * If errata 154 is present the data transfer is acknowledged by the hardware. */ + if (!nrf_drv_usbd_errata_154()) + { + /* Transfer ok - allow status stage */ + nrf_drv_usbd_setup_clear(); + } + } + else if (NRF_USBD_EP_ABORTED == p_event->data.eptransfer.status) + { + /* Just ignore */ + printf("Transfer aborted event on EPOUT0\n"); + } + else + { + printf("Transfer failed on EPOUT0: %d", p_event->data.eptransfer.status); + nrf_drv_usbd_setup_stall(); + } + } + else + { + printf("EP other: %d\n", p_event->data.eptransfer.ep); + /* Nothing to do */ + } + break; + case NRF_DRV_USBD_EVT_SETUP: + { + nrf_drv_usbd_setup_t setup; + nrf_drv_usbd_setup_get(&setup); + switch (setup.bmRequest) + { + case 0x00: // GetStatus + usbd_setup_GetStatus(&setup); + break; + case 0x01: // CleartFeature + usbd_setup_ClearFeature(&setup); + break; + case 0x03: // SetFeature + usbd_setup_SetFeature(&setup); + break; + case 0x05: // SetAddress + //nothing to do, handled by hardware; but don't STALL + break; + case 0x06: // GetDescriptor + usbd_setup_GetDescriptor(&setup); + break; + case 0x08: // GetConfig + usbd_setup_GetConfig(&setup); + break; + case 0x09: // SetConfig + usbd_setup_SetConfig(&setup); + break; + //HID class + case 0x0A: // SetIdle + usbd_setup_SetIdle(&setup); + break; + case 0x0B: // SetProtocol or SetInterface + if (setup.bmRequestType == 0x01) // standard request, recipient=interface + { + usbd_setup_SetInterface(&setup); + } + else if (setup.bmRequestType == 0x21) // class request, recipient=interface + { + usbd_setup_SetProtocol(&setup); + } + else + { + printf("Command 0xB. Unknown request: 0x%2x", setup.bmRequestType); + nrf_drv_usbd_setup_stall(); + } + break; + default: + printf("Unknown request: 0x%2x", setup.bmRequest); + nrf_drv_usbd_setup_stall(); + return; + } + break; + } + default: + printf("unknown usb event\n"); + break; + } +} + + + +static void power_usb_event_handler(nrf_drv_power_usb_evt_t event) +{ + switch (event) + { + case NRF_DRV_POWER_USB_EVT_DETECTED: + printf("USB power detected\n"); + if (!nrf_drv_usbd_is_enabled()) + { + nrf_drv_usbd_enable(); + } + break; + case NRF_DRV_POWER_USB_EVT_REMOVED: + printf("USB power removed\n"); + m_usbd_configured = false; + m_send_mouse_position = false; + if (nrf_drv_usbd_is_started()) + { + nrf_drv_usbd_stop(); + } + if (nrf_drv_usbd_is_enabled()) + { + nrf_drv_usbd_disable(); + } + /* Turn OFF LEDs */ + bsp_board_led_off(LED_USB_STATUS); + bsp_board_led_off(LED_USB_POWER); + break; + case NRF_DRV_POWER_USB_EVT_READY: + printf("USB ready\n"); + bsp_board_led_on(LED_USB_POWER); + if (!nrf_drv_usbd_is_started()) + { + nrf_drv_usbd_start(true); + } + break; + default: + ASSERT(false); + } +} + + +void log_resetreason(void) +{ + /* Reset reason */ + uint32_t rr = nrf_power_resetreas_get(); + printf("Reset reasons:\n"); + if (0 == rr) + { + printf("- NONE\n"); + } + if (0 != (rr & NRF_POWER_RESETREAS_RESETPIN_MASK)) + { + printf("- RESETPIN\n"); + } + if (0 != (rr & NRF_POWER_RESETREAS_DOG_MASK )) + { + printf("- DOG\n"); + } + if (0 != (rr & NRF_POWER_RESETREAS_SREQ_MASK )) + { + printf("- SREQ\n"); + } + if (0 != (rr & NRF_POWER_RESETREAS_LOCKUP_MASK )) + { + printf("- LOCKUP\n"); + } + if (0 != (rr & NRF_POWER_RESETREAS_OFF_MASK )) + { + printf("- OFF\n"); + } + if (0 != (rr & NRF_POWER_RESETREAS_LPCOMP_MASK )) + { + printf("- LPCOMP\n"); + } + if (0 != (rr & NRF_POWER_RESETREAS_DIF_MASK )) + { + printf("- DIF\n"); + } + if (0 != (rr & NRF_POWER_RESETREAS_NFC_MASK )) + { + printf("- NFC\n"); + } + if (0 != (rr & NRF_POWER_RESETREAS_VBUS_MASK )) + { + printf("- VBUS\n"); + } +} + +void usb_init(void) +{ + ret_code_t ret; + + if (NRF_DRV_USBD_ERRATA_ENABLE) + { + nrf_drv_usbd_errata_104(); + nrf_drv_usbd_errata_154(); + } + + + /* USB work starts right here */ + ret = nrf_drv_usbd_init(usbd_event_handler); + APP_ERROR_CHECK(ret); + + /* Configure selected size of the packed on EP0 */ + nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPOUT0, EP0_MAXPACKETSIZE); + nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPIN0, EP0_MAXPACKETSIZE); + + /* Configure LED and button */ + /*bsp_board_init(BSP_INIT_LEDS);*/ + /*bsp_board_led_on(LED_RUNNING);*/ + /*bsp_board_led_on(LED_ACTIVE);*/ + + + if (USBD_POWER_DETECTION) + { + /*printf("Using power detection\n");*/ + static const nrf_drv_power_usbevt_config_t config = + { + .handler = power_usb_event_handler + }; + ret = nrf_drv_power_usbevt_init(&config); + APP_ERROR_CHECK(ret); + } + else + { + /*printf("No USB power detection enabled\r\nStarting USB now\n");*/ + nrf_delay_us(STARTUP_DELAY*1000); + if (!nrf_drv_usbd_is_enabled()) + { + /*printf("enabling\n");*/ + nrf_drv_usbd_enable(); + /*printf("done\n");*/ + ret = ep_configuration(0); + APP_ERROR_CHECK(ret); + } + /* Wait for regulator power up */ + while (NRF_DRV_POWER_USB_STATE_CONNECTED + == + nrf_drv_power_usbstatus_get()) + { + /* Just waiting */ + } + + if (NRF_DRV_POWER_USB_STATE_READY == nrf_drv_power_usbstatus_get()) + { + if (!nrf_drv_usbd_is_started()) + { + nrf_drv_usbd_start(true); + } + } + else + { + nrf_drv_usbd_disable(); + } + } + + + /*while (true)*/ + /*{*/ + /*if (m_system_off_req)*/ + /*{*/ + /*printf("Going to system OFF\n");*/ + /*nrf_power_system_off();*/ + /*}*/ + /*if (m_usbd_suspended != m_usbd_suspend_state_req)*/ + /*{*/ + /*if (m_usbd_suspend_state_req)*/ + /*{*/ + /*m_usbd_suspended = nrf_drv_usbd_suspend();*/ + /*if (m_usbd_suspended)*/ + /*{*/ + /*}*/ + /*}*/ + /*else*/ + /*{*/ + /*m_usbd_suspended = false;*/ + /*}*/ + /*}*/ + + /*if (m_usbd_configured)*/ + /*{*/ + /*}*/ + + /*UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());*/ + /*[>bsp_board_led_off(LED_RUNNING);<]*/ + /* Even if we miss an event enabling USB, + * USB event would wake us up. */ + /*__WFE();*/ + /*[> Clear SEV flag if CPU was woken up by event <]*/ + /*__SEV();*/ + /*__WFE();*/ + /*bsp_board_led_on(LED_RUNNING);*/ + /*}*/ +} diff --git a/nrf52840/usb.h b/nrf52840/usb.h new file mode 100644 index 0000000..ec74a2c --- /dev/null +++ b/nrf52840/usb.h @@ -0,0 +1,6 @@ +#ifndef _USB_H +#define _USB_H + +void usb_init(void); + +#endif