123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- /***********************************************************************************
- Filename: usb_framework.h
- Description: USB library common functionality.
- ***********************************************************************************/
- #ifndef USBFRAMEWORK_H
- #define USBFRAMEWORK_H
- /** \addtogroup module_usb_framework USB Framework (usbfw)
- * \brief This module contains USB status information, functions for initialization, USB device reset
- * handling, and most importantly, the framework for transfers on endpoint 0, FIFO access, and endpoint
- * control.
- *
- * \section section_init Framework Initialization
- * The framework and the USB peripheral unit can be initialized once the crystal oscillator (48 MHz for
- * CC1111/CC2511, 32 MHz for CC2531) is running. This is done by \ref usbfwInit(), which:
- * \li Initializes framework variables
- * \li Enables the USB peripheral unit by setting the \c SLEEP.USB_EN bit
- * \li Enables the pull-up resistor via a GPIO pin
- *
- * When completing the last step, the host will be recognize the USB device, and start the enumeration
- * process. To reply to the shortly incoming standard requests, the call to \ref usbfwInit() must be
- * followed immediately by USB Interrupt \ref section_usbirq_initialization.
- *
- * \section section_endpoint_0_transfers Endpoint 0 Transfers
- * The USB interface uses endpoint 0 to perform setup requests of the standard, vendor and class types.
- * Such transfers consist of three phases:
- * - A setup phase, where an 8-byte \ref USB_SETUP_HEADER is transferred to the device.
- * - An IN/OUT data phase, if the length field of the \ref USB_SETUP_HEADER structure is non-zero.
- * - A handshake phase, where the application can stall the endpoint to indicate error conditions.
- *
- * The setup handler, \ref usbfwSetupHandler(), takes care of the low-level parts of these transfers,
- * including the IN/OUT buffering during the data phase (when there is one). The transfers fall into two
- * categories:
- * - Most standard requests are processed internally, with little or no intervention form the user
- * application. This is done by the \ref module_usb_standard_requests module.
- * - Vendor and class requests are application specific and must always be processed by the application.
- * Whenever such a request is received, the following hooks will be called between the phases:
- * - \ref usbcrHookProcessOut(): Class requests with OUT data phase
- * - \ref usbcrHookProcessIn(): Class requests with IN data phase
- * - \ref usbvrHookProcessOut(): Vendor requests with OUT data phase
- * - \ref usbvrHookProcessIn(): Vendor requests with IN data phase
- *
- * \section section_setup_handler_usage Setup Handler Usage
- * This section describes what is required to make the vendor and class request hooks work. This
- * information also applies to the standard requests that needs application processing
- * (\ref usbsrHookSetDescriptor(), \ref usbsrHookSynchFrame(), and some cases of
- * \ref usbsrHookSetFeature() and \ref usbsrHookClearFeature()).
- *
- * The transactions are made using a clean and efficient interface, consisting of two data structures and
- * the endpoint 0 status byte:
- * - The endpoint status is initially \ref EP_IDLE, which basically means that the setup handler is ready
- * for a new setup phase (a new request). Upon an incoming request, the processing hook is called, and
- * the \ref usbSetupHeader structure contains the 8 bytes received during the setup phase. At this
- * point there are four different outcomes:
- * - If the request is unknown or contains errors, the endpoint should be stalled. This is done by
- * setting the endpoint status to \ref EP_STALL.
- * - If there is no data phase (the length field is zero), the endpoint status should just remain in
- * it's current state, \ref EP_IDLE.
- * - If the request has an IN data phase, the \ref usbSetupData structure must be prepared. This
- * includes setting a pointer to where IN data should be taken from, and the number of bytes to be
- * transferred (usually the same number as indicated by the length field, but it can also be a
- * lower number). The endpoint state is then changed to \ref EP_TX.
- * - If the request has an OUT data phase, the \ref usbSetupData structure must be prepared. This
- * includes setting a pointer to where OUT data should be stored, and the number of bytes to be
- * transferred (always the same number as indicated by the length field). The endpoint state is
- * then changed to \ref EP_RX.
- * - When the data phase is complete, the processing hook function will be called a second time to notify
- * the application. Under normal conditions the endpoint status will be either \ref EP_TX or \ref EP_RX,
- * and does not need to be changed any further (as this is done automatically upon return). If the
- * endpoint status is \ref EP_CANCEL, it means that the USB host cancelled the setup transfer.
- *
- * The following code examples illustrate practical usage (more code is available in the application
- * example projects):
- *
- * \par Example 1: Endpoint 0 Requests With OUT Data phase
- *
- * \code
- * uint8 pLcdBuffer[358];
- *
- * void usbvrHookProcessOut(void) {
- *
- * // When this vendor request is received, we should either update a part of pLcdBuffer[] or leave
- * // it as it is, and then refresh the LCD display. The index field of the setup header contains the
- * // index of the first character to be updated, and the length field how many characters to update.
- * if (usbSetupHeader.request == VR_LCD_UPDATE) {
- *
- * // First the endpoint status is EP_IDLE... (we have just received the Setup packet)
- * if (usbfwData.ep0Status == EP_IDLE) {
- *
- * // There is no new data -> Just refresh the display
- * if (usbSetupHeader.length == 0) {
- * lcdRefresh();
- * // There is no change to the endpoint status in this case
- *
- * // The PC wants to send data that will be stored outside pLcdBuffer -> stall the endpoint!
- * } else if ((usbSetupHeader.length > sizeof(pLcdBuffer) ||
- * (usbSetupHeader.index >= sizeof(pLcdBuffer) ||
- * ((usbSetupHeader.index + usbSetupHeader.length) > sizeof(pLcdBuffer)) {
- * usbfwData.ep0Status = EP_STALL;
- *
- * // Prepare for OUT data phase, setup the data buffer to receive the LCD data
- * } else {
- * usbSetupData.pBuffer = &pLcdBuffer[usbSetupHeader.index];
- * usbSetupData.bytesLeft = usbSetupHeader.length;
- * usbfwData.ep0Status = EP_RX;
- * }
- *
- * // Then the endpoint status is EP_RX (remember: we did that here when setting up the buffer)
- * } else if (usbfwData.ep0Status == EP_RX) {
- * // usbfwSetupHandler() has now updated pLcdBuffer, so all we need to do is refresh the LCD
- * lcdRefresh();
- * // usbfwData.ep0Status is automatically reset to EP_IDLE when returning to usbfwSetupHandler()
- * }
- *
- * // Unknown vendor request?
- * } else {
- * usbfwData.ep0Status = EP_STALL;
- * }
- * }
- * \endcode
- *
- * \par Example 2: Endpoint 0 Requests With IN Data phase
- *
- * \code
- * uint8 keyBufferPos;
- * BOOL blockKeyboard;
- * char pKeyBuffer[150];
- *
- * void usbvrProcessIn(void) {
- *
- * // When this vendor request is received, we should send all registered key-strokes, and reset the
- * // position counter. New keystrokes are blocked during the transfer to avoid overwriting the buffer
- * // before it has been sent to the host.
- * if (usbSetupHeader.request == VR_GET_KEYS) {
- *
- * // First the endpoint status is EP_IDLE...
- * if (usbfwData.ep0Status == EP_IDLE) {
- *
- * // Make sure that we do not send more than the PC asked for
- * if (usbSetupHeader.length < keyBufferPos) {
- * usbfwData.ep0Status = EP_STALL;
- *
- * // Otherwise...
- * } else {
- * // Block for new keystrokes
- * blockKeyboard = TRUE;
- *
- * // Setup the buffer
- * usbSetupData.pBuffer = pKeyBuffer;
- * usbSetupData.bytesLeft = keyBufferPos;
- * usbfwData.ep0Status = EP_TX;
- *
- * // Reset the position counter
- * keyBufferPos = 0;
- * }
- *
- * // Then the endpoint status is EP_TX (remember: we did that here when setting up the buffer)
- * } else if (usbfwData.ep0Status == EP_TX) {
- *
- * // pKeyBuffer has now been sent to the host, so new keystrokes can safely be registered
- * blockKeyboard = FALSE;
- *
- * // usbfwData.ep0Status is automatically reset to EP_IDLE when returning to usbfwSetupHandler()
- * }
- *
- * // Unknown request?
- * } else {
- * usbfwData.ep0Status = EP_STALL;
- * }
- * }
- * \endcode
- *
- * If automated data transfer is not desired, the application should set \c usbfwData.ep0Status to
- * either \ref EP_MANUAL_RX or \ref EP_MANUAL_TX instead of \ref EP_RX or \ref EP_TX, respectively. Until
- * the transfer is completed, the processing hook function (e.g. \ref usbvrHookProcessIn()) will be called
- * at every endpoint 0 interrupt.
- * @{
- */
- #include "usb_board_cfg.h"
- #include "usb_framework_structs.h"
- #ifdef EXTERN
- #undef EXTERN
- #endif
- #ifdef USBFRAMEWORK_C
- #define EXTERN ///< Definition used only for usb_framework.c
- #else
- #define EXTERN extern ///< Definition used in other source files to declare external
- #endif
- //-------------------------------------------------------------------------------------------------------
- /// \name Module Data
- //@{
- EXTERN USBFW_DATA __xdata usbfwData; ///< USBFW internal module data
- //@}
- //-------------------------------------------------------------------------------------------------------
- /// \name Setup Handler Data
- //@{
- EXTERN USB_SETUP_DATA __xdata usbSetupData; ///< Setup handler data phase configuration
- EXTERN USB_SETUP_HEADER __xdata usbSetupHeader; ///< Setup header
- //@}
- //-------------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------------
- /// \name Request Type Fields
- //@{
- // Field masks
- #define RT_MASK_DIR 0x80 ///< Request direction bit mask
- #define RT_MASK_TYPE 0x60 ///< Request type bit mask
- #define RT_MASK_RECIP 0x1F ///< Request recipient bit mask
- // Direction field
- #define RT_DIR_IN 0x80 ///< IN Request
- #define RT_DIR_OUT 0x00 ///< OUT Request
- // Type field
- #define RT_TYPE_STD 0x00 ///< Standard Request
- #define RT_TYPE_CLASS 0x20 ///< Class Request
- #define RT_TYPE_VEND 0x40 ///< Vendor Request
- // Recipient field
- #define RT_RECIP_DEV 0x00 ///< Device Request
- #define RT_RECIP_IF 0x01 ///< Interface Request
- #define RT_RECIP_EP 0x02 ///< Endpoint Request
- #define RT_RECIP_OTHER 0x03 ///< Other Request
- // Type + direction
- #define RT_STD_OUT (RT_TYPE_STD | RT_DIR_OUT) ///< Standard request, direction is OUT
- #define RT_STD_IN (RT_TYPE_STD | RT_DIR_IN) ///< Standard request, direction is IN
- #define RT_VEND_OUT (RT_TYPE_VEND | RT_DIR_OUT) ///< Vendor request, direction is OUT
- #define RT_VEND_IN (RT_TYPE_VEND | RT_DIR_IN) ///< Vendor request, direction is IN
- #define RT_CLASS_OUT (RT_TYPE_CLASS | RT_DIR_OUT) ///< Class request, direction is OUT
- #define RT_CLASS_IN (RT_TYPE_CLASS | RT_DIR_IN) ///< Class request, direction is IN
- // Direction + recepient
- #define RT_OUT_DEVICE (RT_DIR_OUT | RT_RECIP_DEV) ///< Request made to device, direction is OUT
- #define RT_IN_DEVICE (RT_DIR_IN | RT_RECIP_DEV) ///< Request made to device, direction is IN
- #define RT_OUT_INTERFACE (RT_DIR_OUT | RT_RECIP_IF) ///< Request made to interface, direction is OUT
- #define RT_IN_INTERFACE (RT_DIR_IN | RT_RECIP_IF) ///< Request made to interface, direction is IN
- #define RT_OUT_ENDPOINT (RT_DIR_OUT | RT_RECIP_EP) ///< Request made to endpoint, direction is OUT
- #define RT_IN_ENDPOINT (RT_DIR_IN | RT_RECIP_EP) ///< Request made to endpoint, direction is IN
- //@}
- //-------------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------------
- /// \name Vendor and Class Request Hooks
- /// Unused hooks must stall endpoint 0.
- //@{
- /// Hook which is called upon reception of a class request with OUT data phase
- void usbcrHookProcessOut(void);
- /// Hook which is called upon reception of a class request with IN data phase
- void usbcrHookProcessIn(void);
- /// Hook which is called upon reception of a vendor request with OUT data phase
- void usbvrHookProcessOut(void);
- /// Hook which is called upon reception of a vendor request with IN data phase
- void usbvrHookProcessIn(void);
- //@}
- //-------------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------------
- /// \name Endpoint Access Macros
- /// Note that the endpoint control registers are indexed, meaning that an endpoint must be selected
- /// before the control operations listed below can be used. Interrupts using any of these macros, must
- /// save the current selection and restore it upon return.
- //@{
- /// Selects which IN/OUT endpoint (by index 0 to 5) to operate on
- #define USBFW_SELECT_ENDPOINT(n) (USBINDEX = (n))
- /// Gets the currently selected IN/OUT endpoint
- #define USBFW_GET_SELECTED_ENDPOINT() (USBINDEX)
- /// Stalls the selected IN endpoint
- #define USBFW_STALL_IN_ENDPOINT() st (\
- USBCSIL = USBCSIL_SEND_STALL; \
- usbfwData.pEpInStatus[USBINDEX - 1] = EP_HALT; )
- /// Returns the stall condition for the selected IN endpoint
- #define USBFW_IN_ENDPOINT_STALLED() (USBCSIL & USBCSIL_SEND_STALL)
- /// Flushes the FIFO for the selected IN endpoint (flush twice when using double-buffering)
- #define USBFW_FLUSH_IN_ENDPOINT() st (\
- USBCSIL = USBCSIL_FLUSH_PACKET; \
- while (USBCSIL & USBCSIL_FLUSH_PACKET); )
- /// Arms the selected IN endpoint, so that contents of the endpoint FIFO can be sent to the host
- #define USBFW_ARM_IN_ENDPOINT() (USBCSIL = USBCSIL_INPKT_RDY)
- /// Is the selected IN endpoint disarmed?
- #define USBFW_IN_ENDPOINT_DISARMED() !(USBCSIL & USBCSIL_INPKT_RDY)
- /// Is the FIFO for the selected IN endpoint empty?
- #define USBFW_IN_ENDPOINT_FIFO_EMPTY() !(USBCSIL & USBCSIL_PKT_PRESENT)
- /// Stalls the selected OUT endpoint
- #define USBFW_STALL_OUT_ENDPOINT() st ( \
- USBCSOL = USBCSOL_SEND_STALL; \
- usbfwData.pEpOutStatus[USBINDEX - 1] = EP_HALT; \
- }
- /// Returns the stall condition for the selected OUT endpoint
- #define USBFW_OUT_ENDPOINT_STALLED() (USBCSOL & USBCSOL_SEND_STALL)
- /// Flushes the FIFO for the selected OUT endpoint (flush twice when using double-buffering)
- #define USBFW_FLUSH_OUT_ENDPOINT() st(\
- USBCSOL = USBCSOL_FLUSH_PACKET; \
- while (USBCSOL & USBCSOL_FLUSH_PACKET); )
- /// Arms the selected OUT endpoint, so that the FIFO can receive data from the host
- #define USBFW_ARM_OUT_ENDPOINT() (USBCSOL = 0)
- /// Is the selected OUT endpoint disarmed? If so, there is data waiting in the FIFO
- #define USBFW_OUT_ENDPOINT_DISARMED() (USBCSOL & USBCSOL_OUTPKT_RDY)
- /// Returns the number of bytes currently in the FIFO of the selected OUT endpoint, low byte
- #define USBFW_GET_OUT_ENDPOINT_COUNT_LOW() (USBCNTL)
- /// Returns the number of bytes currently in the FIFO of the selected OUT endpoint, high byte
- #define USBFW_GET_OUT_ENDPOINT_COUNT_HIGH() (USBCNTH)
- //@}
- //-------------------------------------------------------------------------------------------------------
- // Little endian
- #define LOBYTEPTR(w) ( (uint8 __generic *)(&(w)) + 1 )
- // Big endian
- //#define LOBYTEPTR(w) ( (uint8 __generic *)&(w) )
- //-------------------------------------------------------------------------------------------------------
- // Function prototypes
- void usbfwInit(void);
- void usbfwResetHandler(void);
- void usbfwSetupHandler(void);
- void usbfwSetAllEpStatus(EP_STATUS status);
- void usbfwWriteFifo(uint8 volatile __xdata *pFifo, uint8 count, void __generic *pData);
- void usbfwReadFifo(uint8 volatile __xdata *pFifo, uint8 count, void __generic *pData);
- //-------------------------------------------------------------------------------------------------------
- //@}
- /*
- +------------------------------------------------------------------------------
- | Copyright 2004-2007 Texas Instruments Incorporated. All rights reserved.
- |
- | IMPORTANT: Your use of this Software is limited to those specific rights
- | granted under the terms of a software license agreement between the user who
- | downloaded the software, his/her employer (which must be your employer) and
- | Texas Instruments Incorporated (the "License"). You may not use this Software
- | unless you agree to abide by the terms of the License. The License limits
- | your use, and you acknowledge, that the Software may not be modified, copied
- | or distributed unless embedded on a Texas Instruments microcontroller or used
- | solely and exclusively in conjunction with a Texas Instruments radio
- | frequency transceiver, which is integrated into your product. Other than for
- | the foregoing purpose, you may not use, reproduce, copy, prepare derivative
- | works of, modify, distribute, perform, display or sell this Software and/or
- | its documentation for any purpose.
- |
- | YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
- | PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
- | INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
- | NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
- | TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
- | NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
- | LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING
- | BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR
- | CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF
- | SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
- | (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
- |
- | Should you have any questions regarding your right to use this Software,
- | contact Texas Instruments Incorporated at www.TI.com.
- |
- +------------------------------------------------------------------------------
- */
- #endif
|