CANUSB4-ISO/Source/USB/picft245.c

887 Zeilen
31 KiB
C

/*------------------------------------------------------------------------------
; PICFT245
;
; FTDI FT245 replacement for CAN_USB in a PIC18F14K50 (C) SPROG DCC 2012
; web: http://www.sprog-dcc.co.uk
; e-mail: sprog@sprog-dcc.co.uk
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, version 3 of the License, as set out
; at <http://www.gnu.org/licenses/>.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
; See the GNU General Public License for more details.
;
; As set out in the GNU General Public License, you must retain and acknowledge
; the statements above relating to copyright and licensing. You must also
; state clearly any modifications made. Please therefore retain this header
; and add documentation of any changes you make. If you distribute a changed
; version, you must make those changes publicly available.
;
; The GNU license requires that if you distribute this software, changed or
; unchanged, or software which includes code from this software, including
; the supply of hardware that incorporates this software, you MUST either
; include the source code or a link to a location where you make the source
; publicly available.
;
------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
;
; Revision History
; 21/03/15 1.4 Revert to buffering complete messages rather than send short
; packets. Improve handling of USB->CAN and CAN->USB contention.
; 20/09/14 1.3 Fixed deadlock in state USB->CAN state machine
; 25/08/14 1.2 Fixed inconsistent endpoint buffer sizes
; 30/12/12 1.1 Replace CAN->USB state machine with tight loop
; Change to Interrupt mode for USB tasks
; Pass incoming CBUS chars direct to USBUSART instead of
; buffering complete Gridconnect messages
; 20/06/12 1.0 Created
;
;-----------------------------------------------------------------------------*/
#include <p18f14k50.h>
//14K50
#pragma config CPUDIV = NOCLKDIV
#pragma config USBDIV = OFF
#pragma config FOSC = HS
#pragma config PLLEN = ON
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRTEN = OFF
#pragma config BOREN = OFF
#pragma config BORV = 30
// #pragma config VREGEN = ON
#pragma config WDTEN = OFF
#pragma config WDTPS = 32768
#pragma config MCLRE = OFF
#pragma config HFOFST = OFF
#pragma config STVREN = ON
#pragma config LVP = OFF
#pragma config XINST = OFF
#pragma config BBSIZ = OFF
#pragma config CP0 = OFF
#pragma config CP1 = OFF
#pragma config CPB = OFF
#pragma config WRT0 = OFF
#pragma config WRT1 = OFF
#pragma config WRTB = OFF
#pragma config WRTC = OFF
#pragma config EBTR0 = OFF
#pragma config EBTR1 = OFF
#pragma config EBTRB = OFF
#include <p18f14k50.h>
#include "GenericTypeDefs.h"
#include "Compiler.h"
#include "./USB/usb.h"
#include "./USB/usb_function_cdc.h"
#include "USB/usb_device.h"
#include "USB/usb.h"
#include "usb_config.h"
#include "HardwareProfile.h"
#include "io.h"
#pragma udata
char USB_Out_Buffer[CDC_DATA_OUT_EP_SIZE];
char USB_In_Buffer[CDC_DATA_IN_EP_SIZE];
unsigned char NextUSBOut;
unsigned char NextUSBOut;
unsigned char LastUSBIn; // Number of characters in the buffer
unsigned char USBcp; // current position within the buffer
unsigned char USB_In_Data_Rdy;
unsigned char USB_Out_Data_Rdy;
USB_HANDLE lastTransmission;
unsigned char usb_in;
unsigned char usb_in_state;
#define U_IDLE 0
#define U_IDLE2 1
#define U_RDY 2
#define U_OUT 3
unsigned char can_in;
static void InitializeSystem(void);
void ProcessIO(void);
void USBDeviceTasks(void);
void YourHighPriorityISRCode();
void YourLowPriorityISRCode();
void USBCBSendResume(void);
void UserInit(void);
unsigned char usbGetChar(void);
unsigned char usbIsDataRdy(void);
#pragma udata
#pragma interrupt isr_high
void isr_high(void) {
#if defined(USB_INTERRUPT)
USBDeviceTasks();
#endif
}
//
// Low priority interrupt. Not used.
//
#pragma interruptlow isr_low
void isr_low(void) {
Nop();
Nop();
}
/*
* Interrupt vectors
*/
#pragma code high_vector=0x8
void HIGH_INT_VECT(void)
{
_asm GOTO isr_high _endasm
}
#pragma code low_vector=0x18
void LOW_INT_VECT(void)
{
_asm GOTO isr_low _endasm
}
#pragma code
void main(void)
{
InitializeSystem();
#if defined(USB_INTERRUPT)
if(USB_BUS_SENSE && (USBGetDeviceState() == DETACHED_STATE))
{
USBDeviceAttach();
}
#endif
while(1)
{
// Application-specific tasks.
// Application related code may be added here, or in the ProcessIO() function.
ProcessIO();
// Non-blocking state machine to handle USB -> CAN
switch (usb_in_state) {
case U_IDLE:
// Wait until data is received from host
if (usbIsDataRdy()) {
usb_in = usbGetChar();
PORTBbits.UDAV = 1;
usb_in_state = U_RDY;
}
break;
case U_IDLE2:
// usb_in already holds a byte received from USB but CAN PIC started a transfer
// to USB before we could send the byte in usb_in to CAN. Spin around here and
// U_RDY waiting for UREQ handshake when the transfer to USB has finished.
usb_in_state = U_RDY;
break;
case U_RDY:
if (PORTBbits.UREQ && (PORTBbits.CDAV == 0)) {
// CAN PIC is ready to receive and has nothing to send to USB.
Nop();
// Drive data bits out
TRISC = 0;
Nop();
PORTC = usb_in;
Nop();
PORTBbits.UDAV = 0;
usb_in_state = U_OUT;
} else if (PORTBbits.CDAV == 1) {
// CAN PIC has a CAN frame to send to USB so give it priority.
// CAN PIC uses a tight loop to send data to USB so this can only happen
// at the beginning of a frame, not in the maiddle of a frame.
usb_in_state = U_IDLE2;
}
break;
case U_OUT:
// Wait for CAN interface to acknowledge data
if (PORTBbits.UREQ == 0) {
TRISC = 0xFF;
usb_in_state = U_IDLE;
}
break;
}
if ((usb_in_state == U_IDLE) || (usb_in_state == U_IDLE2)) {
// USB->CAN handshke is idle
if (PORTBbits.CDAV && (NextUSBOut < CDC_DATA_OUT_EP_SIZE-1)) {
// CAN PIC has data available and will send it in tight loop to keep
// the CAN buffers as empty as possible, so we loop here until the whole
// packet is received.
PORTBbits.CREQ = 1;
while (PORTBbits.CDAV == 1) {
// wait for handshake
;
}
Nop();
Nop();
// put data into buffer and append a zero
USB_Out_Buffer[NextUSBOut] = PORTC;
if (PORTC == ';') {
// Received ';' so send the complete gridconnect packet
USB_Out_Data_Rdy = 1;
}
PORTBbits.CREQ = 0;
NextUSBOut++;
USB_Out_Buffer[NextUSBOut] = 0;
} else if (NextUSBOut >= CDC_DATA_OUT_EP_SIZE-1) {
// Should never happen, but send the buffer if it fills up
USB_Out_Data_Rdy = 1;
}
}
}
}
/********************************************************************
* Function: static void InitializeSystem(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: InitializeSystem is a centralize initialization
* routine. All required USB initialization routines
* are called from here.
*
* User application initialization routine should
* also be called from here.
*
* Note: None
*******************************************************************/
static void InitializeSystem(void)
{
unsigned char i;
PORTC = PORTC_INIT;
PORTB = PORTB_INIT;
PORTA = PORTA_INIT;
// Port pull-ups
WPUA = 0x38;
WPUB = 0xF0;
TRISC = PORTC_DDR;
TRISB = PORTB_DDR;
TRISA = PORTA_DDR;
USB_In_Data_Rdy = 0;
USB_Out_Data_Rdy = 0;
ANSEL = 0; // Default all pins to digital
ANSELH = 0;
INTCON = 0;
// Initialize the arrays
for (i=0; i<sizeof(USB_Out_Buffer); i++)
{
USB_Out_Buffer[i] = 0;
}
NextUSBOut = 0;
LastUSBIn = 0;
lastTransmission = 0;
usb_in_state = U_IDLE;
USBDeviceInit(); //usb_device.c. Initializes USB module SFRs and firmware
//variables to known states.
}
/******************************************************************************
* Function: void mySetLineCodingHandler(void)
*
* PreCondition: USB_CDC_SET_LINE_CODING_HANDLER is defined
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This function gets called when a SetLineCoding command
* is sent on the bus. This function will evaluate the request
* and determine if the application should update the baudrate
* or not.
*
* Note:
*
*****************************************************************************/
#if defined(USB_CDC_SET_LINE_CODING_HANDLER)
void mySetLineCodingHandler(void)
{
}
#endif
/********************************************************************
* Function: void ProcessIO(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This function is a place holder for other user
* routines. It is a mixture of both USB and
* non-USB tasks.
*
* Note: None
*******************************************************************/
void ProcessIO(void)
{
// User Application USB tasks
if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) { return; }
// If the previous USB data has been consumed, check for new data from USB.
if (USB_In_Data_Rdy == 0) {
LastUSBIn = getsUSBUSART(USB_In_Buffer, CDC_DATA_IN_EP_SIZE);
if(LastUSBIn > 0)
{
USB_In_Data_Rdy = 1; // signal buffer full
USBcp = 0; // Reset the current position
}
}
// Send data to USB
if((USBUSARTIsTxTrfReady()) && USB_Out_Data_Rdy) {
putUSBUSART(&USB_Out_Buffer[0], NextUSBOut);
NextUSBOut = 0;
USB_Out_Data_Rdy = 0;
}
CDCTxService();
} //end ProcessIO
/*
* usbIsDataRdy()
*
* Check if there is any data available
*/
unsigned char usbIsDataRdy(void) {
if (USB_In_Data_Rdy) {
return 1;
} else {
return 0;
}
}
/*
* usbGetChar()
*
* Get data from the input buffer
*/
unsigned char usbGetChar(void) {
unsigned char ret = 0;
if(USB_In_Data_Rdy) {
ret = USB_In_Buffer[USBcp];
++USBcp;
if (USBcp == LastUSBIn)
// All of the data has been consumed
USB_In_Data_Rdy = 0;
}
return ret;
}
// ******************************************************************************************************
// ************** USB Callback Functions ****************************************************************
// ******************************************************************************************************
// The USB firmware stack will call the callback functions USBCBxxx() in response to certain USB related
// events. For example, if the host PC is powering down, it will stop sending out Start of Frame (SOF)
// packets to your device. In response to this, all USB devices are supposed to decrease their power
// consumption from the USB Vbus to <2.5mA each. The USB module detects this condition (which according
// to the USB specifications is 3+ms of no bus activity/SOF packets) and then calls the USBCBSuspend()
// function. You should modify these callback functions to take appropriate actions for each of these
// conditions. For example, in the USBCBSuspend(), you may wish to add code that will decrease power
// consumption from Vbus to <2.5mA (such as by clock switching, turning off LEDs, putting the
// microcontroller to sleep, etc.). Then, in the USBCBWakeFromSuspend() function, you may then wish to
// add code that undoes the power saving things done in the USBCBSuspend() function.
// The USBCBSendResume() function is special, in that the USB stack will not automatically call this
// function. This function is meant to be called from the application firmware instead. See the
// additional comments near the function.
/******************************************************************************
* Function: void USBCBSuspend(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Call back that is invoked when a USB suspend is detected
*
* Note: None
*****************************************************************************/
void USBCBSuspend(void)
{
//Example power saving code. Insert appropriate code here for the desired
//application behavior. If the microcontroller will be put to sleep, a
//process similar to that shown below may be used:
//ConfigureIOPinsForLowPower();
//SaveStateOfAllInterruptEnableBits();
//DisableAllInterruptEnableBits();
//EnableOnlyTheInterruptsWhichWillBeUsedToWakeTheMicro(); //should enable at least USBActivityIF as a wake source
//Sleep();
//RestoreStateOfAllPreviouslySavedInterruptEnableBits(); //Preferrably, this should be done in the USBCBWakeFromSuspend() function instead.
//RestoreIOPinsToNormal(); //Preferrably, this should be done in the USBCBWakeFromSuspend() function instead.
//IMPORTANT NOTE: Do not clear the USBActivityIF (ACTVIF) bit here. This bit is
//cleared inside the usb_device.c file. Clearing USBActivityIF here will cause
//things to not work as intended.
}
/******************************************************************************
* Function: void USBCBWakeFromSuspend(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: The host may put USB peripheral devices in low power
* suspend mode (by "sending" 3+ms of idle). Once in suspend
* mode, the host may wake the device back up by sending non-
* idle state signalling.
*
* This call back is invoked when a wakeup from USB suspend
* is detected.
*
* Note: None
*****************************************************************************/
void USBCBWakeFromSuspend(void)
{
// If clock switching or other power savings measures were taken when
// executing the USBCBSuspend() function, now would be a good time to
// switch back to normal full power run mode conditions. The host allows
// a few milliseconds of wakeup time, after which the device must be
// fully back to normal, and capable of receiving and processing USB
// packets. In order to do this, the USB module must receive proper
// clocking (IE: 48MHz clock must be available to SIE for full speed USB
// operation).
}
/********************************************************************
* Function: void USBCB_SOF_Handler(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: The USB host sends out a SOF packet to full-speed
* devices every 1 ms. This interrupt may be useful
* for isochronous pipes. End designers should
* implement callback routine as necessary.
*
* Note: None
*******************************************************************/
void USBCB_SOF_Handler(void)
{
// No need to clear UIRbits.SOFIF to 0 here.
// Callback caller is already doing that.
}
/*******************************************************************
* Function: void USBCBErrorHandler(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: The purpose of this callback is mainly for
* debugging during development. Check UEIR to see
* which error causes the interrupt.
*
* Note: None
*******************************************************************/
void USBCBErrorHandler(void)
{
// No need to clear UEIR to 0 here.
// Callback caller is already doing that.
// Typically, user firmware does not need to do anything special
// if a USB error occurs. For example, if the host sends an OUT
// packet to your device, but the packet gets corrupted (ex:
// because of a bad connection, or the user unplugs the
// USB cable during the transmission) this will typically set
// one or more USB error interrupt flags. Nothing specific
// needs to be done however, since the SIE will automatically
// send a "NAK" packet to the host. In response to this, the
// host will normally retry to send the packet again, and no
// data loss occurs. The system will typically recover
// automatically, without the need for application firmware
// intervention.
// Nevertheless, this callback function is provided, such as
// for debugging purposes.
}
/*******************************************************************
* Function: void USBCBCheckOtherReq(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: When SETUP packets arrive from the host, some
* firmware must process the request and respond
* appropriately to fulfill the request. Some of
* the SETUP packets will be for standard
* USB "chapter 9" (as in, fulfilling chapter 9 of
* the official USB specifications) requests, while
* others may be specific to the USB device class
* that is being implemented. For example, a HID
* class device needs to be able to respond to
* "GET REPORT" type of requests. This
* is not a standard USB chapter 9 request, and
* therefore not handled by usb_device.c. Instead
* this request should be handled by class specific
* firmware, such as that contained in usb_function_hid.c.
*
* Note: None
*******************************************************************/
void USBCBCheckOtherReq(void)
{
USBCheckCDCRequest();
}//end
/*******************************************************************
* Function: void USBCBStdSetDscHandler(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: The USBCBStdSetDscHandler() callback function is
* called when a SETUP, bRequest: SET_DESCRIPTOR request
* arrives. Typically SET_DESCRIPTOR requests are
* not used in most applications, and it is
* optional to support this type of request.
*
* Note: None
*******************************************************************/
void USBCBStdSetDscHandler(void)
{
// Must claim session ownership if supporting this request
}//end
/*******************************************************************
* Function: void USBCBInitEP(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This function is called when the device becomes
* initialized, which occurs after the host sends a
* SET_CONFIGURATION (wValue not = 0) request. This
* callback function should initialize the endpoints
* for the device's usage according to the current
* configuration.
*
* Note: None
*******************************************************************/
void USBCBInitEP(void)
{
CDCInitEP();
}
/********************************************************************
* Function: void USBCBSendResume(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: The USB specifications allow some types of USB
* peripheral devices to wake up a host PC (such
* as if it is in a low power suspend to RAM state).
* This can be a very useful feature in some
* USB applications, such as an Infrared remote
* control receiver. If a user presses the "power"
* button on a remote control, it is nice that the
* IR receiver can detect this signalling, and then
* send a USB "command" to the PC to wake up.
*
* The USBCBSendResume() "callback" function is used
* to send this special USB signalling which wakes
* up the PC. This function may be called by
* application firmware to wake up the PC. This
* function will only be able to wake up the host if
* all of the below are true:
*
* 1. The USB driver used on the host PC supports
* the remote wakeup capability.
* 2. The USB configuration descriptor indicates
* the device is remote wakeup capable in the
* bmAttributes field.
* 3. The USB host PC is currently sleeping,
* and has previously sent your device a SET
* FEATURE setup packet which "armed" the
* remote wakeup capability.
*
* If the host has not armed the device to perform remote wakeup,
* then this function will return without actually performing a
* remote wakeup sequence. This is the required behavior,
* as a USB device that has not been armed to perform remote
* wakeup must not drive remote wakeup signalling onto the bus;
* doing so will cause USB compliance testing failure.
*
* This callback should send a RESUME signal that
* has the period of 1-15ms.
*
* Note: This function does nothing and returns quickly, if the USB
* bus and host are not in a suspended condition, or are
* otherwise not in a remote wakeup ready state. Therefore, it
* is safe to optionally call this function regularly, ex:
* anytime application stimulus occurs, as the function will
* have no effect, until the bus really is in a state ready
* to accept remote wakeup.
*
* When this function executes, it may perform clock switching,
* depending upon the application specific code in
* USBCBWakeFromSuspend(). This is needed, since the USB
* bus will no longer be suspended by the time this function
* returns. Therefore, the USB module will need to be ready
* to receive traffic from the host.
*
* The modifiable section in this routine may be changed
* to meet the application needs. Current implementation
* temporary blocks other functions from executing for a
* period of ~3-15 ms depending on the core frequency.
*
* According to USB 2.0 specification section 7.1.7.7,
* "The remote wakeup device must hold the resume signaling
* for at least 1 ms but for no more than 15 ms."
* The idea here is to use a delay counter loop, using a
* common value that would work over a wide range of core
* frequencies.
* That value selected is 1800. See table below:
* ==========================================================
* Core Freq(MHz) MIP RESUME Signal Period (ms)
* ==========================================================
* 48 12 1.05
* 4 1 12.6
* ==========================================================
* * These timing could be incorrect when using code
* optimization or extended instruction mode,
* or when having other interrupts enabled.
* Make sure to verify using the MPLAB SIM's Stopwatch
* and verify the actual signal on an oscilloscope.
*******************************************************************/
void USBCBSendResume(void)
{
static WORD delay_count;
//First verify that the host has armed us to perform remote wakeup.
//It does this by sending a SET_FEATURE request to enable remote wakeup,
//usually just before the host goes to standby mode (note: it will only
//send this SET_FEATURE request if the configuration descriptor declares
//the device as remote wakeup capable, AND, if the feature is enabled
//on the host (ex: on Windows based hosts, in the device manager
//properties page for the USB device, power management tab, the
//"Allow this device to bring the computer out of standby." checkbox
//should be checked).
if(USBGetRemoteWakeupStatus() == TRUE)
{
//Verify that the USB bus is in fact suspended, before we send
//remote wakeup signalling.
if(USBIsBusSuspended() == TRUE)
{
USBMaskInterrupts();
//Clock switch to settings consistent with normal USB operation.
USBCBWakeFromSuspend();
USBSuspendControl = 0;
USBBusIsSuspended = FALSE; //So we don't execute this code again,
//until a new suspend condition is detected.
//Section 7.1.7.7 of the USB 2.0 specifications indicates a USB
//device must continuously see 5ms+ of idle on the bus, before it sends
//remote wakeup signalling. One way to be certain that this parameter
//gets met, is to add a 2ms+ blocking delay here (2ms plus at
//least 3ms from bus idle to USBIsBusSuspended() == TRUE, yeilds
//5ms+ total delay since start of idle).
delay_count = 3600U;
do
{
delay_count--;
}while(delay_count);
//Now drive the resume K-state signalling onto the USB bus.
USBResumeControl = 1; // Start RESUME signaling
delay_count = 1800U; // Set RESUME line for 1-13 ms
do
{
delay_count--;
}while(delay_count);
USBResumeControl = 0; //Finished driving resume signalling
USBUnmaskInterrupts();
}
}
}
/*******************************************************************
* Function: void USBCBEP0DataReceived(void)
*
* PreCondition: ENABLE_EP0_DATA_RECEIVED_CALLBACK must be
* defined already (in usb_config.h)
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This function is called whenever a EP0 data
* packet is received. This gives the user (and
* thus the various class examples a way to get
* data that is received via the control endpoint.
* This function needs to be used in conjunction
* with the USBCBCheckOtherReq() function since
* the USBCBCheckOtherReq() function is the apps
* method for getting the initial control transfer
* before the data arrives.
*
* Note: None
*******************************************************************/
#if defined(ENABLE_EP0_DATA_RECEIVED_CALLBACK)
void USBCBEP0DataReceived(void)
{
}
#endif
/*******************************************************************
* Function: BOOL USER_USB_CALLBACK_EVENT_HANDLER(
* USB_EVENT event, void *pdata, WORD size)
*
* PreCondition: None
*
* Input: USB_EVENT event - the type of event
* void *pdata - pointer to the event data
* WORD size - size of the event data
*
* Output: None
*
* Side Effects: None
*
* Overview: This function is called from the USB stack to
* notify a user application that a USB event
* occured. This callback is in interrupt context
* when the USB_INTERRUPT option is selected.
*
* Note: None
*******************************************************************/
BOOL USER_USB_CALLBACK_EVENT_HANDLER(int event, void *pdata, WORD size)
{
switch(event)
{
case EVENT_TRANSFER:
//Add application specific callback task or callback function here if desired.
break;
case EVENT_SOF:
USBCB_SOF_Handler();
break;
case EVENT_SUSPEND:
USBCBSuspend();
break;
case EVENT_RESUME:
USBCBWakeFromSuspend();
break;
case EVENT_CONFIGURED:
USBCBInitEP();
break;
case EVENT_SET_DESCRIPTOR:
USBCBStdSetDscHandler();
break;
case EVENT_EP0_REQUEST:
USBCBCheckOtherReq();
break;
case EVENT_BUS_ERROR:
USBCBErrorHandler();
break;
case EVENT_TRANSFER_TERMINATED:
//Add application specific callback task or callback function here if desired.
//The EVENT_TRANSFER_TERMINATED event occurs when the host performs a CLEAR
//FEATURE (endpoint halt) request on an application endpoint which was
//previously armed (UOWN was = 1). Here would be a good place to:
//1. Determine which endpoint the transaction that just got terminated was
// on, by checking the handle value in the *pdata.
//2. Re-arm the endpoint if desired (typically would be the case for OUT
// endpoints).
break;
default:
break;
}
return TRUE;
}
/** EOF main.c *************************************************/