diff --git a/nrf52840/Makefile b/nrf52840/Makefile index 58a18b9..4c14b79 100644 --- a/nrf52840/Makefile +++ b/nrf52840/Makefile @@ -143,7 +143,7 @@ CFLAGS += -DFLOAT_ABI_HARD CFLAGS += -DNRF52840_XXAA CFLAGS += -mcpu=cortex-m4 CFLAGS += -mthumb -mabi=aapcs -CFLAGS += -Wall -Werror +CFLAGS += -Wall CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 # keep every function in a separate section, this allows linker to discard unused ones CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing diff --git a/nrf52840/list.py b/nrf52840/list.py new file mode 100644 index 0000000..aef6252 --- /dev/null +++ b/nrf52840/list.py @@ -0,0 +1,21 @@ +from fido2.hid import CtapHidDevice +from fido2.client import Fido2Client +from fido2.pyu2f import hidtransport +import sys +from random import randint +import array + + +# Locate a device +#for d in CtapHidDevice.list_devices(): + #print(d) +selector = hidtransport.HidUsageSelector +for d in hidtransport.hid.Enumerate(): + print('1',d) + if selector(d): + try: + dev = hidtransport.hid.Open(d['path']) + print('2',dev) + except OSError: + # Insufficient permissions to access device + pass diff --git a/nrf52840/main.c b/nrf52840/main.c index eb0d785..de57f88 100644 --- a/nrf52840/main.c +++ b/nrf52840/main.c @@ -47,15 +47,16 @@ * This file contains the source code for a sample application to blink LEDs. * */ - +#define DEBUG #include -#include #include #include "nrf.h" #include "nrf_gpio.h" #include "nrf_delay.h" #include "boards.h" +#include "nrf_strerror.h" + #include "nrf_drv_rtc.h" #include "nrf_drv_clock.h" @@ -79,6 +80,18 @@ const nrf_drv_rtc_t rtc = NRF_DRV_RTC_INSTANCE(0); /**< Declaring an instance of nrf_drv_rtc for RTC0. */ +#define printf(fmt,...) SEGGER_RTT_printf(0, fmt, ##__VA_ARGS__); + + +/*lint -save -e14 */ +void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) +{ + error_info_t * e = (error_info_t *)info; + SEGGER_RTT_printf(0, "Error: %d: %s at %d:%s\n",e->err_code, nrf_strerror_get(e->err_code), e->line_num, e->p_file_name); + while(1) + ; +} + /** @brief Function starting the internal LFCLK XTAL oscillator. @@ -116,10 +129,10 @@ 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"); + /*bsp_board_init(BSP_INIT_LEDS);*/ + /*lfclk_config();*/ + /*rtc_config();*/ + /*SEGGER_RTT_printf(0, "Hello FIDO2\n");*/ uint32_t count; int i = 0; @@ -143,550 +156,1284 @@ 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 "app_util_platform.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_usbd.h" -#include "app_usbd_core.h" -#include "app_usbd_hid_generic.h" -#include "app_usbd_hid_mouse.h" -#include "app_usbd_hid_kbd.h" #include "app_error.h" #include "bsp.h" -#include "bsp_config.h" - #include "bsp_cli.h" #include "nrf_cli.h" - -#define NRF_LOG_INFO(info) SEGGER_RTT_printf(0,"%s\r\n",info) +/*#include "nrf_cli_uart.h"*/ /** - * @brief Enable USB power detection + * @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 HID generic class interface number. - * */ -#define HID_GENERIC_INTERFACE 0 - -/** - * @brief HID generic class endpoint number. - * */ -#define HID_GENERIC_EPIN NRF_DRV_USBD_EPIN1 - -/** - * @brief Mouse speed (value sent via HID when board button is pressed). - * */ -#define CONFIG_MOUSE_MOVE_SPEED (3) - -/** - * @brief Mouse move repeat time in milliseconds - */ -#define CONFIG_MOUSE_MOVE_TIME_MS (5) - - -/* GPIO used as LED & buttons in this example */ -#define LED_USB_START (BSP_BOARD_LED_0) -#define LED_HID_REP_IN (BSP_BOARD_LED_2) - -#define BTN_MOUSE_X_POS 0 -#define BTN_MOUSE_Y_POS 1 -#define BTN_MOUSE_LEFT 2 -#define BTN_MOUSE_RIGHT 3 - -/** - * @brief Left button mask in buttons report - */ -#define HID_BTN_LEFT_MASK (1U << 0) - -/** - * @brief Right button mask in buttons report - */ -#define HID_BTN_RIGHT_MASK (1U << 1) - -/* HID report layout */ -#define HID_BTN_IDX 0 /**< Button bit mask position */ -#define HID_X_IDX 1 /**< X offset position */ -#define HID_Y_IDX 2 /**< Y offset position */ -#define HID_W_IDX 3 /**< Wheel position */ -#define HID_REP_SIZE 4 /**< The size of the report */ - -/** - * @brief Number of reports defined in report descriptor. - */ -#define REPORT_IN_QUEUE_SIZE 1 - -/** - * @brief Size of maximum output report. HID generic class will reserve - * this buffer size + 1 memory space. */ -#define REPORT_OUT_MAXSIZE 0 - -/** - * @brief HID generic class endpoints count. - * */ -#define HID_GENERIC_EP_COUNT 1 - -/** - * @brief List of HID generic class endpoints. - * */ -#define ENDPOINT_LIST() \ -( \ - HID_GENERIC_EPIN \ -) - -/** - * @brief Additional key release events + * @brief Startup delay * - * This example needs to process release events of used buttons + * Number of microseconds to start USBD after powering up. + * Kind of port insert debouncing. */ -enum { - BSP_USER_EVENT_RELEASE_0 = BSP_EVENT_KEY_LAST + 1, /**< Button 0 released */ - BSP_USER_EVENT_RELEASE_1, /**< Button 1 released */ - BSP_USER_EVENT_RELEASE_2, /**< Button 2 released */ - BSP_USER_EVENT_RELEASE_3, /**< Button 3 released */ - BSP_USER_EVENT_RELEASE_4, /**< Button 4 released */ - BSP_USER_EVENT_RELEASE_5, /**< Button 5 released */ - BSP_USER_EVENT_RELEASE_6, /**< Button 6 released */ - BSP_USER_EVENT_RELEASE_7, /**< Button 7 released */ +#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) */\ + 0x01, 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 1 +#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, 0x01, /* 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, applies to all subsequent items */\ + 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 }; -/** - * @brief HID generic mouse action types - */ -typedef enum { - HID_GENERIC_MOUSE_X, - HID_GENERIC_MOUSE_Y, - HID_GENERIC_MOUSE_BTN_LEFT, - HID_GENERIC_MOUSE_BTN_RIGHT, -} hid_generic_mouse_action_t; +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] /** - * @brief User event handler. - * */ -static void hid_user_ev_handler(app_usbd_class_inst_t const * p_inst, - app_usbd_hid_user_event_t event); - -/** - * @brief Reuse HID mouse report descriptor for HID generic class - */ -APP_USBD_HID_GENERIC_SUBCLASS_REPORT_DESC(mouse_desc,APP_USBD_HID_MOUSE_REPORT_DSC_BUTTON(2)); - -static const app_usbd_hid_subclass_desc_t * reps[] = {&mouse_desc}; - -/*lint -save -e26 -e64 -e123 -e505 -e651*/ - -/** - * @brief Global HID generic instance - */ -APP_USBD_HID_GENERIC_GLOBAL_DEF(m_app_hid_generic, - HID_GENERIC_INTERFACE, - hid_user_ev_handler, - ENDPOINT_LIST(), - reps, - REPORT_IN_QUEUE_SIZE, - REPORT_OUT_MAXSIZE, - APP_USBD_HID_SUBCLASS_BOOT, - APP_USBD_HID_PROTO_MOUSE); - -/*lint -restore*/ - - -/** - * @brief Mouse state + * @brief USB configured flag * - * Current mouse status + * The flag that is used to mark the fact that USB is configured and ready + * to transmit data */ -struct +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) { - int16_t acc_x; /**< Accumulated x state */ - int16_t acc_y; /**< Accumulated y state */ - uint8_t btn; /**< Current btn state */ - uint8_t last_btn; /**< Last transfered button state */ -}m_mouse_state; - -/** - * @brief Mark the ongoing transmission - * - * Marks that the report buffer is busy and cannot be used until transmission finishes - * or invalidates (by USB reset or suspend event). - */ -static bool m_report_pending; - -/** - * @brief Timer to repeat mouse move - */ -APP_TIMER_DEF(m_mouse_move_timer); - -/** - * @brief Get maximal allowed accumulated value - * - * Function gets maximal value from the accumulated input. - * @sa m_mouse_state::acc_x, m_mouse_state::acc_y - */ -static int8_t hid_acc_for_report_get(int16_t acc) -{ - if(acc > INT8_MAX) + if ( index == 1 ) { - return INT8_MAX; + 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); + m_usbd_configured = true; + nrf_drv_usbd_setup_clear(); } - else if(acc < INT8_MIN) + else if ( index == 0 ) { - return INT8_MIN; + nrf_drv_usbd_ep_disable(NRF_DRV_USBD_EPIN1); + m_usbd_configured = false; + nrf_drv_usbd_setup_clear(); } else { - return (int8_t)(acc); + return NRF_ERROR_INVALID_PARAM; } + return NRF_SUCCESS; } /** - * @brief Internal function that process mouse state + * @name Processing setup requests * - * This function checks current mouse state and tries to send - * new report if required. - * If report sending was successful it clears accumulated positions - * and mark last button state that was transfered. + * @{ */ -static void hid_generic_mouse_process_state(void) +/** + * @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) { - if (m_report_pending) + /* 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) + { + NRF_LOG_ERROR("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; + } + } + } + break; + default: + break; // Just go to stall + } + NRF_LOG_ERROR("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; + } + } + } + NRF_LOG_ERROR("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; + } + } + } + NRF_LOG_ERROR("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: + printf("string manufacturer: %d bytes\n", sizeof(get_descriptor_string_manuf)); + 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? + if (((p_setup->wValue) & 0xFF) == 1) + { + respond_setup_data( + p_setup, + get_descriptor_endpoint_1, + 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 + } + + NRF_LOG_ERROR("Unknown descriptor requested: 0x%2x, type: 0x%2x or value: 0x%2x", + 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; + } + } + } + NRF_LOG_ERROR("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; - if ((m_mouse_state.acc_x != 0) || - (m_mouse_state.acc_y != 0) || - (m_mouse_state.btn != m_mouse_state.last_btn)) - { - ret_code_t ret; - static uint8_t report[HID_REP_SIZE]; - /* We have some status changed that we need to transfer */ - report[HID_BTN_IDX] = m_mouse_state.btn; - report[HID_X_IDX] = (uint8_t)hid_acc_for_report_get(m_mouse_state.acc_x); - report[HID_Y_IDX] = (uint8_t)hid_acc_for_report_get(m_mouse_state.acc_y); - /* Start the transfer */ - ret = app_usbd_hid_generic_in_report_set( - &m_app_hid_generic, - report, - sizeof(report)); - if (ret == NRF_SUCCESS) - { - m_report_pending = true; - m_mouse_state.last_btn = report[HID_BTN_IDX]; - CRITICAL_REGION_ENTER(); - /* This part of the code can fail if interrupted by BSP keys processing. - * Lock interrupts to be safe */ - m_mouse_state.acc_x -= (int8_t)report[HID_X_IDX]; - m_mouse_state.acc_y -= (int8_t)report[HID_Y_IDX]; - CRITICAL_REGION_EXIT(); - } } + NRF_LOG_ERROR("Set Idle wrong type: 0x%2x.", p_setup->bmRequestType); + nrf_drv_usbd_setup_stall(); } -/** - * @brief HID generic IN report send handling - * */ -static void hid_generic_mouse_action(hid_generic_mouse_action_t action, int8_t param) +static void usbd_setup_SetInterface( + nrf_drv_usbd_setup_t const * const p_setup) { - CRITICAL_REGION_ENTER(); - /* - * Update mouse state - */ - switch (action) + //no alternate setting is supported - STALL always + NRF_LOG_ERROR("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) { - case HID_GENERIC_MOUSE_X: - m_mouse_state.acc_x += param; + //accept any value + nrf_drv_usbd_setup_clear(); + return; + } + NRF_LOG_ERROR("Set Protocol wrong type: 0x%2x.", p_setup->bmRequestType); + nrf_drv_usbd_setup_stall(); +} + +/** @} */ /* End of processing setup requests functions */ + + +static void usbd_event_handler(nrf_drv_usbd_evt_t const * const p_event) +{ + switch (p_event->type) + { + case NRF_DRV_USBD_EVT_SUSPEND: + NRF_LOG_INFO("SUSPEND state detected"); + m_usbd_suspend_state_req = true; + break; + case NRF_DRV_USBD_EVT_RESUME: + NRF_LOG_INFO("RESUMING from suspend"); + m_usbd_suspend_state_req = false; + break; + case NRF_DRV_USBD_EVT_WUREQ: + NRF_LOG_INFO("RemoteWU initiated"); + 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 HID_GENERIC_MOUSE_Y: - m_mouse_state.acc_y += param; - break; - case HID_GENERIC_MOUSE_BTN_RIGHT: - if(param == 1) + } + case NRF_DRV_USBD_EVT_SOF: + { + static uint32_t cycle = 0; + ++cycle; + if ((cycle % (m_usbd_configured ? 500 : 100)) == 0) { - m_mouse_state.btn |= HID_BTN_RIGHT_MASK; + bsp_board_led_invert(LED_USB_STATUS); + } + break; + } + case NRF_DRV_USBD_EVT_EPTRANSFER: + if (NRF_DRV_USBD_EPIN1 == p_event->data.eptransfer.ep) + { + m_send_mouse_position = false; + } + 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 */ + NRF_LOG_INFO("Transfer aborted event on EPIN0"); } else { - m_mouse_state.btn &= ~HID_BTN_RIGHT_MASK; + NRF_LOG_ERROR("Transfer failed on EPIN0: %d", p_event->data.eptransfer.status); + nrf_drv_usbd_setup_stall(); } - break; - case HID_GENERIC_MOUSE_BTN_LEFT: - if(param == 1) + } + 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) { - m_mouse_state.btn |= HID_BTN_LEFT_MASK; + /* 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 */ + NRF_LOG_INFO("Transfer aborted event on EPOUT0"); } else { - m_mouse_state.btn &= ~HID_BTN_LEFT_MASK; + NRF_LOG_ERROR("Transfer failed on EPOUT0: %d", p_event->data.eptransfer.status); + nrf_drv_usbd_setup_stall(); } - break; - } - CRITICAL_REGION_EXIT(); -} - -/** - * @brief Class specific event handler. - * - * @param p_inst Class instance. - * @param event Class specific event. - * */ -static void hid_user_ev_handler(app_usbd_class_inst_t const * p_inst, - app_usbd_hid_user_event_t event) -{ - switch (event) - { - case APP_USBD_HID_USER_EVT_OUT_REPORT_READY: - { - /* No output report defined for this example.*/ - ASSERT(0); - break; } - case APP_USBD_HID_USER_EVT_IN_REPORT_DONE: + else { - m_report_pending = false; - hid_generic_mouse_process_state(); - bsp_board_led_invert(LED_HID_REP_IN); - break; + /* Nothing to do */ } - case APP_USBD_HID_USER_EVT_SET_BOOT_PROTO: + break; + case NRF_DRV_USBD_EVT_SETUP: { - NRF_LOG_INFO("SET_BOOT_PROTO"); - break; - } - case APP_USBD_HID_USER_EVT_SET_REPORT_PROTO: - { - NRF_LOG_INFO("SET_REPORT_PROTO"); - break; - } - default: - break; - } -} - -/** - * @brief USBD library specific event handler. - * - * @param event USBD library event. - * */ -static void usbd_user_ev_handler(app_usbd_event_type_t event) -{ - switch (event) - { - case APP_USBD_EVT_DRV_SOF: - break; - case APP_USBD_EVT_DRV_RESET: - m_report_pending = false; - break; - case APP_USBD_EVT_DRV_SUSPEND: - m_report_pending = false; - app_usbd_suspend_req(); // Allow the library to put the peripheral into sleep mode - bsp_board_leds_off(); - break; - case APP_USBD_EVT_DRV_RESUME: - m_report_pending = false; - bsp_board_led_on(LED_USB_START); - break; - case APP_USBD_EVT_STARTED: - m_report_pending = false; - bsp_board_led_on(LED_USB_START); - break; - case APP_USBD_EVT_STOPPED: - app_usbd_disable(); - bsp_board_leds_off(); - break; - case APP_USBD_EVT_POWER_DETECTED: - NRF_LOG_INFO("USB power detected"); - if (!nrf_drv_usbd_is_enabled()) + nrf_drv_usbd_setup_t setup; + nrf_drv_usbd_setup_get(&setup); + switch (setup.bmRequest) { - app_usbd_enable(); + 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 + { + NRF_LOG_ERROR("Command 0xB. Unknown request: 0x%2x", setup.bmRequestType); + nrf_drv_usbd_setup_stall(); + } + break; + default: + NRF_LOG_ERROR("Unknown request: 0x%2x", setup.bmRequest); + nrf_drv_usbd_setup_stall(); + return; } break; - case APP_USBD_EVT_POWER_REMOVED: - NRF_LOG_INFO("USB power removed"); - app_usbd_stop(); - break; - case APP_USBD_EVT_POWER_READY: - NRF_LOG_INFO("USB ready"); - app_usbd_start(); - break; - default: - break; + } + default: + break; } } -static void mouse_move_timer_handler(void * p_context) + +static void move_mouse_pointer(void) { - UNUSED_PARAMETER(p_context); - bool used = false; + static uint32_t databuffer; - if (bsp_button_is_pressed(BTN_MOUSE_X_POS)) + if (!m_usbd_configured) + return; + if (!m_send_mouse_position) { - hid_generic_mouse_action(HID_GENERIC_MOUSE_X, CONFIG_MOUSE_MOVE_SPEED); - used = true; - } - if (bsp_button_is_pressed(BTN_MOUSE_Y_POS)) - { - hid_generic_mouse_action(HID_GENERIC_MOUSE_Y, CONFIG_MOUSE_MOVE_SPEED); - used = true; - } + 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++; - if(!used) - { - UNUSED_RETURN_VALUE(app_timer_stop(m_mouse_move_timer)); + /* 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 bsp_event_callback(bsp_event_t ev) +static void power_usb_event_handler(nrf_drv_power_usb_evt_t event) { - switch ((unsigned int)ev) + switch (event) { - case CONCAT_2(BSP_EVENT_KEY_, BTN_MOUSE_X_POS): - hid_generic_mouse_action(HID_GENERIC_MOUSE_X, CONFIG_MOUSE_MOVE_SPEED); - UNUSED_RETURN_VALUE(app_timer_start(m_mouse_move_timer, APP_TIMER_TICKS(CONFIG_MOUSE_MOVE_TIME_MS), NULL)); - break; - - case CONCAT_2(BSP_EVENT_KEY_, BTN_MOUSE_Y_POS): - hid_generic_mouse_action(HID_GENERIC_MOUSE_Y, CONFIG_MOUSE_MOVE_SPEED); - UNUSED_RETURN_VALUE(app_timer_start(m_mouse_move_timer, APP_TIMER_TICKS(CONFIG_MOUSE_MOVE_TIME_MS), NULL)); - break; - - case CONCAT_2(BSP_EVENT_KEY_, BTN_MOUSE_RIGHT): - hid_generic_mouse_action(HID_GENERIC_MOUSE_BTN_RIGHT, 1); - break; - case CONCAT_2(BSP_USER_EVENT_RELEASE_, BTN_MOUSE_RIGHT): - hid_generic_mouse_action(HID_GENERIC_MOUSE_BTN_RIGHT, -1); - break; - - case CONCAT_2(BSP_EVENT_KEY_, BTN_MOUSE_LEFT): - hid_generic_mouse_action(HID_GENERIC_MOUSE_BTN_LEFT, 1); - break; - case CONCAT_2(BSP_USER_EVENT_RELEASE_, BTN_MOUSE_LEFT): - hid_generic_mouse_action(HID_GENERIC_MOUSE_BTN_LEFT, -1); - break; - - default: - return; // no implementation needed + case NRF_DRV_POWER_USB_EVT_DETECTED: + NRF_LOG_INFO("USB power detected"); + if (!nrf_drv_usbd_is_enabled()) + { + nrf_drv_usbd_enable(); + } + break; + case NRF_DRV_POWER_USB_EVT_REMOVED: + NRF_LOG_INFO("USB power removed"); + 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: + NRF_LOG_INFO("USB ready"); + 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; + } +} -/** - * @brief Auxiliary internal macro - * - * Macro used only in @ref init_bsp to simplify the configuration - */ -#define INIT_BSP_ASSIGN_RELEASE_ACTION(btn) \ - APP_ERROR_CHECK( \ - bsp_event_to_button_action_assign( \ - btn, \ - BSP_BUTTON_ACTION_RELEASE, \ - (bsp_event_t)CONCAT_2(BSP_USER_EVENT_RELEASE_, btn)) \ - ) +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; - SEGGER_RTT_printf(0, "USB %d\n", __LINE__); - ret = bsp_init(BSP_INIT_BUTTONS, bsp_event_callback); + ret = bsp_init(BSP_INIT_BUTTONS, bsp_evt_handler); APP_ERROR_CHECK(ret); - SEGGER_RTT_printf(0, "USB %d\n", __LINE__); - INIT_BSP_ASSIGN_RELEASE_ACTION(BTN_MOUSE_LEFT ); - INIT_BSP_ASSIGN_RELEASE_ACTION(BTN_MOUSE_RIGHT); - - /* Configure LEDs */ - bsp_board_init(BSP_INIT_LEDS); - SEGGER_RTT_printf(0, "USB %d\n", __LINE__); + 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_event_callback); - SEGGER_RTT_printf(0, "USB %d\n", __LINE__); + ret = bsp_cli_init(bsp_evt_handler); APP_ERROR_CHECK(ret); - SEGGER_RTT_printf(0, "USB %d\n", __LINE__); + /*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(); + NRF_LOG_INFO("Reset reasons:"); + if (0 == rr) + { + NRF_LOG_INFO("- NONE"); + } + if (0 != (rr & NRF_POWER_RESETREAS_RESETPIN_MASK)) + { + NRF_LOG_INFO("- RESETPIN"); + } + if (0 != (rr & NRF_POWER_RESETREAS_DOG_MASK )) + { + NRF_LOG_INFO("- DOG"); + } + if (0 != (rr & NRF_POWER_RESETREAS_SREQ_MASK )) + { + NRF_LOG_INFO("- SREQ"); + } + if (0 != (rr & NRF_POWER_RESETREAS_LOCKUP_MASK )) + { + NRF_LOG_INFO("- LOCKUP"); + } + if (0 != (rr & NRF_POWER_RESETREAS_OFF_MASK )) + { + NRF_LOG_INFO("- OFF"); + } + if (0 != (rr & NRF_POWER_RESETREAS_LPCOMP_MASK )) + { + NRF_LOG_INFO("- LPCOMP"); + } + if (0 != (rr & NRF_POWER_RESETREAS_DIF_MASK )) + { + NRF_LOG_INFO("- DIF"); + } + if (0 != (rr & NRF_POWER_RESETREAS_NFC_MASK )) + { + NRF_LOG_INFO("- NFC"); + } + if (0 != (rr & NRF_POWER_RESETREAS_VBUS_MASK )) + { + NRF_LOG_INFO("- VBUS"); + } } int usb_main(void) { ret_code_t ret; - static const app_usbd_config_t usbd_config = { - .ev_state_proc = usbd_user_ev_handler - }; - - - SEGGER_RTT_printf(0, "USB %d\n", __LINE__); - /*ret = nrf_drv_clock_init();*/ - /*APP_ERROR_CHECK(ret);*/ - SEGGER_RTT_printf(0, "USB %d\n", __LINE__); - - nrf_drv_clock_lfclk_request(NULL); - SEGGER_RTT_printf(0, "USB %d\n", __LINE__); - - while(!nrf_drv_clock_lfclk_is_running()) - { - /* Just waiting */ - } - SEGGER_RTT_printf(0, "USB %d\n", __LINE__); - - ret = app_timer_init(); - APP_ERROR_CHECK(ret); - SEGGER_RTT_printf(0, "USB %d\n", __LINE__); - - ret = app_timer_create(&m_mouse_move_timer, APP_TIMER_MODE_REPEATED, mouse_move_timer_handler); - APP_ERROR_CHECK(ret); - SEGGER_RTT_printf(0, "USB %d\n", __LINE__); + UNUSED_RETURN_VALUE(NRF_LOG_INIT(NULL)); + init_power_clock(); init_bsp(); init_cli(); - NRF_LOG_INFO("Hello USB!"); - SEGGER_RTT_printf(0, "USB %d\n", __LINE__); - ret = app_usbd_init(&usbd_config); + NRF_LOG_INFO("USDB example started."); + if (NRF_DRV_USBD_ERRATA_ENABLE) + { + NRF_LOG_INFO("USB errata 104 %s", (uint32_t)(nrf_drv_usbd_errata_104() ? "enabled" : "disabled")); + NRF_LOG_INFO("USB errata 154 %s", (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); - NRF_LOG_INFO("USBD HID generic example started."); + /* 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); - app_usbd_class_inst_t const * class_inst_generic; - class_inst_generic = app_usbd_hid_generic_class_inst_get(&m_app_hid_generic); - ret = app_usbd_class_append(class_inst_generic); - APP_ERROR_CHECK(ret); if (USBD_POWER_DETECTION) { - ret = app_usbd_power_events_enable(); + 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 { NRF_LOG_INFO("No USB power detection enabled\r\nStarting USB now"); + 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 */ + } - app_usbd_enable(); - app_usbd_start(); + 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) { - while (app_usbd_event_queue_process()) + if (m_system_off_req) { - /* Nothing to do */ + NRF_LOG_INFO("Going to system OFF"); + 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; + } } - hid_generic_mouse_process_state(); - /*nrf_cli_process(&m_cli_uart);*/ + 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 + { + NRF_LOG_INFO(" TX pointer"); + move_mouse_pointer(); + } + } + } + + /*nrf_cli_process(&m_cli_uart);*/ UNUSED_RETURN_VALUE(NRF_LOG_PROCESS()); - /* Sleep CPU only if there was no interrupt since last loop processing */ + 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/sdk_config.h b/nrf52840/sdk_config.h index 09c29ee..933c023 100644 --- a/nrf52840/sdk_config.h +++ b/nrf52840/sdk_config.h @@ -1339,7 +1339,7 @@ #endif // GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS - Number of lower power input pins #ifndef GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS -#define GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 1 +#define GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 4 #endif // GPIOTE_CONFIG_IRQ_PRIORITY - Interrupt priority @@ -1641,7 +1641,7 @@ // NRFX_CLOCK_ENABLED - nrfx_clock - CLOCK peripheral driver //========================================================== #ifndef NRFX_CLOCK_ENABLED -#define NRFX_CLOCK_ENABLED 0 +#define NRFX_CLOCK_ENABLED 1 #endif // NRFX_CLOCK_CONFIG_LF_SRC - LF Clock Source @@ -1863,7 +1863,7 @@ // NRFX_GPIOTE_ENABLED - nrfx_gpiote - GPIOTE peripheral driver //========================================================== #ifndef NRFX_GPIOTE_ENABLED -#define NRFX_GPIOTE_ENABLED 0 +#define NRFX_GPIOTE_ENABLED 1 #endif // NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS - Number of lower power input pins #ifndef NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS @@ -2366,7 +2366,7 @@ // NRFX_POWER_ENABLED - nrfx_power - POWER peripheral driver //========================================================== #ifndef NRFX_POWER_ENABLED -#define NRFX_POWER_ENABLED 0 +#define NRFX_POWER_ENABLED 1 #endif // NRFX_POWER_CONFIG_IRQ_PRIORITY - Interrupt priority