Newer
Older
mbed-os / targets / TARGET_Cypress / TARGET_PSOC6 / mtb-hal-cat1 / include / cyhal_usb_dev.h
@Dustin Crossman Dustin Crossman on 4 Jun 2021 18 KB Fix file modes.
/***************************************************************************//**
* \file cyhal_usb_dev.h
*
* \brief
* Provides a high level interface for interacting with the Cypress USB Device.
* This interface abstracts out the chip specific details.
* If any chip specific functionality is necessary, or performance is critical
* the low level functions can be used directly.
*
********************************************************************************
* \copyright
* Copyright 2019-2021 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

/**
* \addtogroup group_hal_usb_dev USB Device
* \ingroup group_hal
* \{
* High level interface for interacting with the USB Device.
*
* This block supports one control endpoint (EP0) and one or more data endpoints.
* See the device datasheet for the number of data endpoints supported.
*
* Four transfer types are supported (see \ref cyhal_usb_dev_ep_type_t):
* * Bulk
* * Interrupt
* * Isochronous
* * Control
*
* \section section_usb_dev_features Features
* * Complies with USB specification 2.0
* * Supports full-speed peripheral device operation with a signaling bit rate of 12 Mbps.
* * Configurable D+ AND D- pins  using \ref cyhal_gpio_t
* * Configurable Interrupt and Callback assignment on USB events like SOF, Bus Reset, EP0 Setup and EP0 transaction.
* * Configurable USB device address.
* * Configurable USB Endpoints (except for Endpoint 0)
*
* \section section_usb_dev_quickstart Quick Start
* \ref cyhal_usb_dev_init can be used for initialization of USB by providing the USBDP and USBDM pins.
* See \ref subsection_usb_dev_snippet_1 for the initialization code snippet.
*
* \section section_usb_dev_snippets Code snippets
*
* \subsection subsection_usb_dev_snippet_1 Snippet 1: USB Device Initialization
* The following section initializes the USB Device and assigns the USBDM and USBDP pins using
* \ref cyhal_usb_dev_init. The clock parameter <b>clk</b> is optional and need not be provided (NULL),
* to generate and use an available clock resource with a default frequency. The device can be made
* physically visible to the USB Host by using \ref cyhal_usb_dev_connect
*
* \snippet hal_usb_dev.c snippet_cyhal_usb_dev_init
*
*
* \subsection subsection_usb_dev_snippet_2 Snippet 2: Handling USB Event Completion
* USB events (see \ref cyhal_usb_dev_event_t) like Bus Reset, EP0 transaction, EP0 Setup can be mapped to an interrupt and assigned
* a callback function. The callback function needs to be first registered using
* \ref cyhal_usb_dev_register_event_callback. Use different callback functions to handle events individually.
*
* \snippet hal_usb_dev.c snippet_cyhal_usb_dev_event
*
*
* \subsection subsection_usb_dev_snippet_3 Snippet 3: Custom USB Interrupt Handler
* The following section illustrates how to set up the IRQ interrupt handler for USB device. Inside the handler
* \ref cyhal_usb_dev_process_irq has been used to process the interrupts.
*
* \snippet hal_usb_dev.c snippet_cyhal_usb_dev_irq
*
*
* \subsection subsection_usb_dev_snippet_4 Snippet 4: Adding an Endpoint and Handling its Interrupts
* The following section shows how to add endpoint to the USB device and configure the endpoint using
* \ref cyhal_usb_dev_endpoint_add. The interrupts associated with the endpoints are handled by a
* callback function registered using \ref cyhal_usb_dev_register_endpoint_callback.
* The endpoint can also be configured using <a href="https://www.cypress.com/ModusToolboxUSBConfig">ModusToolbox USB Configurator</a>
*
* \snippet hal_usb_dev.c snippet_cyhal_usb_dev_endpoint
*/

#pragma once

#include <stdint.h>
#include <stdbool.h>
#include "cy_result.h"
#include "cyhal_hw_types.h"

#if defined(__cplusplus)
extern "C" {
#endif

/** \addtogroup group_hal_results_usbdev USB Device HAL Results
 *  USB Device specific return codes
 *  \ingroup group_hal_results
 *  \{ *//**
 */

/** The usb error */
#define CYHAL_USB_DEV_RSLT_ERR                          \
    (CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_USB, 0))
/** The driver configuration is not supported by the HAL */
#define CYHAL_USB_DEV_RSLT_ERR_BAD_DRV_CFG              \
    (CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_USB, 1))
/** The configuration of USB clock failed */
#define CYHAL_USB_DEV_RSLT_ERR_CLK_CFG                  \
    (CYHAL_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_USB, 2))

/**
 * \}
 */

/**
 * \addtogroup group_hal_usb_dev_endpoint Endpoint
 * \{
 * APIs relating to endpoint management
 */

/** Returns true if endpoint direction is IN */
#define CYHAL_USB_DEV_IS_IN_EP(endpoint)        (0U != (0x80U & (uint32_t) (endpoint)))

/** Returns endpoint number (type uint32_t) */
#define CYHAL_USB_DEV_GET_EP_NUM(endpoint)      ((uint32_t) (endpoint) & 0x0FU)

/** Returns endpoint index (type uint32_t) */
#define CYHAL_USB_DEV_GET_EP_IDX(endpoint)      (CYHAL_USB_DEV_GET_EP_NUM(endpoint) - 1U)

/** USB Device Endpoints types */
typedef enum
{
    CYHAL_USB_DEV_EP_TYPE_CTRL = 0,
    CYHAL_USB_DEV_EP_TYPE_ISO  = 1,
    CYHAL_USB_DEV_EP_TYPE_BULK = 2,
    CYHAL_USB_DEV_EP_TYPE_INT  = 3
} cyhal_usb_dev_ep_type_t;

/** \} group_hal_usb_dev_endpoint */


/**
 * \addtogroup group_hal_usb_dev_common Common
 * \{
 */

/** Service Callback Events */
typedef enum
{
    CYHAL_USB_DEV_EVENT_BUS_RESET,  /**< Callback hooked to bus reset interrupt */
    CYHAL_USB_DEV_EVENT_EP0_SETUP,  /**< Callback hooked to endpoint 0 SETUP packet interrupt */
    CYHAL_USB_DEV_EVENT_EP0_IN,     /**< Callback hooked to endpoint 0 IN packet interrupt */
    CYHAL_USB_DEV_EVENT_EP0_OUT,    /**< Callback hooked to endpoint 0 OUT packet interrupt */
} cyhal_usb_dev_event_t;


/**
 * USB endpoint address (consists from endpoint number and direction)
 */
typedef uint8_t cyhal_usb_dev_ep_t;

/**
 * Callback handler for USB Device interrupt
 */
typedef void (*cyhal_usb_dev_irq_callback_t)(void);

/**
 * Callback handler for the transfer completion event for data endpoints (not applicable for endpoint 0)
 */
typedef void (* cyhal_usb_dev_endpoint_callback_t)(cyhal_usb_dev_ep_t endpoint);

/** Callback handler for the events for USB Device */
typedef void (*cyhal_usb_dev_event_callback_t)(void);

/** Callback handler for the events for USB Device */
typedef void (*cyhal_usb_dev_sof_callback_t)(uint32_t frame_number);


/**
 * Initialize the USB instance.
 *
 * @param[out] obj    Pointer to a USB object. The caller must allocate the
 *  memory for this object but the init function will initialize its contents.
 * @param[in] dp      The D+ pin to initialize
 * @param[in] dm      The D- pin to initialize
 * @param[in] clk     The clock to use can be shared, if not provided a new clock will be allocated
 *
 * @return The status of the initialization request
 */
 cy_rslt_t cyhal_usb_dev_init(cyhal_usb_dev_t *obj, cyhal_gpio_t dp, cyhal_gpio_t dm, const cyhal_clock_t *clk);

/**
 * Power down the USB instance
 *
 * Disable interrupts and stop sending events.
 *
 * @param[in,out] obj The USB device object
 */
 void cyhal_usb_dev_free(cyhal_usb_dev_t *obj);

/**
 * Make the USB device visible to the USB host
 *
 * Enable either the D+ or D- pull-up so the host can detect
 * the presence of this device.
 *
 * @param[in,out] obj The USB device object
 */
 void cyhal_usb_dev_connect(cyhal_usb_dev_t *obj);

/**
 * Detach the USB device
 *
 * Disable the D+ and D- pull-up and stop responding to
 * USB traffic.
 *
 * @param[in,out] obj The USB device object
 */
 void cyhal_usb_dev_disconnect(cyhal_usb_dev_t *obj);

 /**
  * Suspend the USB phy. This allows the device to enter deepsleep.
  * Any data left any USB EP buffers will be lost, when device go into deepsleep.
  * Call \ref cyhal_usb_dev_resume to resume USB from deepsleep.
  *
  * @param[in] obj The usb device object
  */
 void cyhal_usb_dev_suspend(cyhal_usb_dev_t *obj);

/**
 * Resume the USB phy from a suspended state. \see cyhal_usb_dev_suspend
 *
 * @param[in] obj The usb device object
 */
 void cyhal_usb_dev_resume(cyhal_usb_dev_t *obj);

/**
 * Set this device to the configured state
 *
 * Enable added endpoints if they are not enabled
 * already.
 *
 * @param[in,out] obj The USB device object
 */
 void cyhal_usb_dev_set_configured(cyhal_usb_dev_t *obj);

/**
 * Leave the configured state
 *
 * This is a notification to the USBPhy indicating that the device
 * is leaving the configured state. The USBPhy can disable all
 * endpoints other than endpoint 0.
 *
 * @param[in,out] obj The USB device object
 */
 void cyhal_usb_dev_set_unconfigured(cyhal_usb_dev_t *obj);

/**
 * Configure start of frame interrupt enablement.
 *
 * @param[in,out] obj The USB device object
 * @param[in] enable  True to turn on interrupt and start calling sof callback on every frame,
 *                    False to turn off interrupt and stop calling sof callback.
 */
 void cyhal_usb_dev_sof_enable(cyhal_usb_dev_t *obj, bool enable);

/**
 * Set the USBPhy's address
 *
 * @param[in,out] obj The USB device object
 * @param[in] address This device's USB address
 */
 void cyhal_usb_dev_set_address(cyhal_usb_dev_t *obj, uint8_t address);

/** \} group_hal_usb_dev_common */

/**
 * \addtogroup group_hal_usb_dev_ep0 EP0
 * \{
 * APIs relating specifically to management of endpoint zero
 */

/**
 * Get wMaxPacketSize of endpoint 0.
 * The endpoint 0 has dedicated buffer.
 *
 * @param[in,out] obj       The USB device object
 *
 * @return The size allocated for endpoint 0
 */
uint32_t cyhal_usb_dev_ep0_get_max_packet(cyhal_usb_dev_t *obj);

/**
 * Read the contents of the SETUP packet
 *
 * @param[in,out] obj The USB device object
 * @param[in] buffer  Buffer to fill with data
 * @param[in] size    Size of buffer passed in
 */
 void cyhal_usb_dev_ep0_setup_read_result(cyhal_usb_dev_t *obj, uint8_t *buffer, uint32_t size);

/**
 * Start receiving a packet of up to wMaxPacketSize on endpoint 0
 *
 * @param[in,out] obj The USB device object
 * @param[in] buffer  Buffer to fill with the data read
 * @param[in] size    Size of buffer
 */
 void cyhal_usb_dev_ep0_read(cyhal_usb_dev_t *obj, uint8_t *buffer, uint32_t size);

/**
 * Read the contents of a received packet
 *
 * @param[in,out] obj  The USB device object
 *
 * @return Actual number of bytes that was read
 */
 uint32_t cyhal_usb_dev_ep0_read_result(cyhal_usb_dev_t *obj);

/**
 * Write a packet on endpoint 0
 *
 * @param[in,out] obj The USB device object
 * @param[in] buffer  Buffer fill with data to send
 * @param[in] size    Size of data to send
 *
 * @return The number of bytes that were written.
 */
 uint32_t cyhal_usb_dev_ep0_write(cyhal_usb_dev_t *obj, uint8_t *buffer, uint32_t size);

/**
 * Protocol stall on endpoint 0.
 * Stall all IN and OUT packets on endpoint 0 until a SETUP packet is received.
 *
 * @param[in,out] obj The USB device object
 *
 * @note The stall is cleared automatically when a setup packet is received
 */
 void cyhal_usb_dev_ep0_stall(cyhal_usb_dev_t *obj);

/** \} group_hal_usb_dev_ep0 */

/**
 * \addtogroup group_hal_usb_dev_endpoint
 * \{
 */

/**
 * Configure an endpoint.
 *
 * @param[in,out] obj    The USB device object
 * @param[in] alloc      True to allocates buffer for the endpoint, false to skip allocation
 * @param[in] enable     True to enable endpoint operation, false to skip enablement
 * @param[in] endpoint   Endpoint to configure and enable
 * @param[in] max_packet The maximum packet size that can be sent or received
 * @param[in] type       The type of endpoint (does not care when enable parameter is false)
 *
 * @return The status of the endpoint add request
 *
 * @note
 * - This function cannot be used to configure endpoint 0. That must be done
 *   with cyhal_usb_dev_ep0_get_max_packet.
 * - After endpoint was enabled it must be removed with cyhal_usb_dev_endpoint_remove
 *   and then enabled again.
 */
cy_rslt_t cyhal_usb_dev_endpoint_add(cyhal_usb_dev_t *obj, bool alloc, bool enable ,cyhal_usb_dev_ep_t endpoint, uint32_t max_packet, cyhal_usb_dev_ep_type_t type);

/**
 * Disable an endpoint
 *
 * @param[in,out] obj  The USB device object
 * @param[in] endpoint Endpoint to disable
 *
 * @return The status of the endpoint remove request
 */
 cy_rslt_t cyhal_usb_dev_endpoint_remove(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint);

/**
 * Perform a functional stall on the given endpoint
 *
 * Set the HALT feature for this endpoint so that all further
 * communication is aborted.
 *
 * @param[in,out] obj  The USB device object
 * @param[in] endpoint Endpoint to stall
 *
 * @return The status of the endpoint stall request
 */
 cy_rslt_t cyhal_usb_dev_endpoint_stall(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint);

/**
 * Unstall the endpoint
 *
 * Clear the HALT feature on this endpoint so communication can
 * resume.
 *
 * @param[in,out] obj  The USB device object
 * @param[in] endpoint Endpoint to stall
 *
 * @return The status of the endpoint unstall request
 */
 cy_rslt_t cyhal_usb_dev_endpoint_unstall(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint);

/**
 * Return the endpoint stall state
 *
 * @param[in,out] obj    The USB device object
 * @param[in] endpoint   Endpoint to check stall state
 *
 * @return True if endpoint stalled, false otherwise.
 */
 bool cyhal_usb_dev_endpoint_is_stalled(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint);

/**
 * Start a read on the given endpoint
 *
 * @param[in,out] obj  The USB device object
 * @param[in] endpoint Endpoint to start the read on
 * @param[in] data     Buffer to fill with data
 * @param[in] size     Size of the read buffer. This must be at least
 *                     the max packet size for this endpoint.
 *
 * @return The status of start a read operation
 */
 cy_rslt_t cyhal_usb_dev_endpoint_read(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, uint8_t *data, uint32_t size);

/**
 * Finish a read on the given endpoint
 *
 * @param[in,out] obj   The USB device object
 * @param[in] endpoint  Endpoint to check
 * @param[out] act_size Actual number of bytes that was read
 *
 * @return The status of a finish read
 */
 cy_rslt_t cyhal_usb_dev_endpoint_read_result(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, uint32_t *act_size);

/**
 * Start a write on the given endpoint
 *
 * @param[in,out] obj  The USB device object
 * @param[in] endpoint Endpoint to write to
 * @param[in] data     Buffer to write
 * @param[in] size     Size of data to write
 *
 * @return The status of a write request
 */
 cy_rslt_t cyhal_usb_dev_endpoint_write(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, uint8_t const *data, uint32_t size);

/**
 * Abort the current transfer if it has not yet been sent
 *
 * @param[in,out] obj  The USB device object
 * @param[in] endpoint Endpoint to abort the transfer on. It is implementation defined
 * if this function has an effect on receive endpoints.
 *
 * @return The status of an abort request
 *
 * @note
 * For the ISOC endpoints in pending state this function does not wait for
 * bus activity completion because these endpoints do not have handshake and are
 * always accessible to the Host. Therefore it is safe to call this function for
 * ISOC endpoint when the Host will not access them during abort.
 */
 cy_rslt_t cyhal_usb_dev_endpoint_abort(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint);

/** \} group_hal_usb_dev_endpoint */

/**
 * \addtogroup group_hal_usb_dev_common Common
 * \{
 */

 /** Register a USB Device callback handler
 *
 * This function will be called when the USB interrupt is triggered. This interrupt can be
 * enabled or disabled using \ref cyhal_usb_dev_irq_enable.
 *
 * @param[in,out] obj The USB device object
 * @param[in] callback The event handler function which will be invoked when the event fires
 *
 * @return The status of the register_irq_callback request
 */
cy_rslt_t cyhal_usb_dev_register_irq_callback(cyhal_usb_dev_t *obj, cyhal_usb_dev_irq_callback_t callback);

/**
 * Configure USB Device event enablement.
 *
 * When the interrupt is enabled and triggered, the function specified by \ref cyhal_usb_dev_register_irq_callback will be called.
 *
 * @param[in,out] obj The usb device object
 * @param[in] enable  True to turn on events, False to turn off
 */
void cyhal_usb_dev_irq_enable(cyhal_usb_dev_t *obj, bool enable);

/**
 *  Default USB Device interrupt handler.
 *
 * @param[in,out] obj The USB device object
 */
void cyhal_usb_dev_process_irq(cyhal_usb_dev_t *obj);

/**
 * The USB Device endpoint complete callback handler registration
 *
 * @param[in,out] obj  The USB device object
 * @param[in] endpoint Endpoint to registers handler
 * @param[in] callback  The callback handler which will be invoked when the endpoint comp
 *
 * \ingroup group_hal_usb_dev_endpoint
 */
void cyhal_usb_dev_register_endpoint_callback(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, cyhal_usb_dev_endpoint_callback_t callback);

/**
 * The USB Device event complete callback handler registration. The events are defined by x type.
 *
 * @param[in,out] obj The USB device object
 * @param[in] event   The event that triggers the callback, see \ref cyhal_usb_dev_event_t
 * @param[in] callback The callback handler which will be invoked when the interrupt fires
 */
void cyhal_usb_dev_register_event_callback(cyhal_usb_dev_t *obj, cyhal_usb_dev_event_t event, cyhal_usb_dev_event_callback_t callback);

/**
 * The USB Device start of frame (SOF) complete callback handler registration.
 *
 * @param[in,out] obj The USB device object
 * @param[in] callback The callback handler which will be invoked when the interrupt fires
 */
void cyhal_usb_dev_register_sof_callback( cyhal_usb_dev_t *obj, cyhal_usb_dev_sof_callback_t callback);

/** \} group_hal_usb_dev_common */

#if defined(__cplusplus)
}
#endif

#ifdef CYHAL_USB_DEV_IMPL_HEADER
#include CYHAL_USB_DEV_IMPL_HEADER
#endif /* CYHAL_USB_DEV_IMPL_HEADER */

/** \} group_hal_usb_dev */