commit 96acb2268b12ff19b81dd7441ee8074d529c5b83 Author: jasonsanctuary Date: Sun Sep 17 14:12:49 2017 -0700 Initial commit diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..05a3fb1 --- /dev/null +++ b/Makefile @@ -0,0 +1,108 @@ +# +# There exist several targets which are by default empty and which can be +# used for execution of your targets. These targets are usually executed +# before and after some main targets. They are: +# +# .build-pre: called before 'build' target +# .build-post: called after 'build' target +# .clean-pre: called before 'clean' target +# .clean-post: called after 'clean' target +# .clobber-pre: called before 'clobber' target +# .clobber-post: called after 'clobber' target +# .all-pre: called before 'all' target +# .all-post: called after 'all' target +# .help-pre: called before 'help' target +# .help-post: called after 'help' target +# +# Targets beginning with '.' are not intended to be called on their own. +# +# Main targets can be executed directly, and they are: +# +# build build a specific configuration +# clean remove built files from a configuration +# clobber remove all built files +# all build all configurations +# help print help mesage +# +# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and +# .help-impl are implemented in nbproject/makefile-impl.mk. +# +# Available make variables: +# +# CND_BASEDIR base directory for relative paths +# CND_DISTDIR default top distribution directory (build artifacts) +# CND_BUILDDIR default top build directory (object files, ...) +# CONF name of current configuration +# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration) +# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration) +# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration) +# CND_PACKAGE_DIR_${CONF} directory of package (current configuration) +# CND_PACKAGE_NAME_${CONF} name of package (current configuration) +# CND_PACKAGE_PATH_${CONF} path to package (current configuration) +# +# NOCDDL + + +# Environment +MKDIR=mkdir +CP=cp +CCADMIN=CCadmin +RANLIB=ranlib + + +# build +build: .build-post + +.build-pre: +# Add your pre 'build' code here... + +.build-post: .build-impl +# Add your post 'build' code here... + + +# clean +clean: .clean-post + +.clean-pre: +# Add your pre 'clean' code here... + +.clean-post: .clean-impl +# Add your post 'clean' code here... + + +# clobber +clobber: .clobber-post + +.clobber-pre: +# Add your pre 'clobber' code here... + +.clobber-post: .clobber-impl +# Add your post 'clobber' code here... + + +# all +all: .all-post + +.all-pre: +# Add your pre 'all' code here... + +.all-post: .all-impl +# Add your post 'all' code here... + + +# help +help: .help-post + +.help-pre: +# Add your pre 'help' code here... + +.help-post: .help-impl +# Add your post 'help' code here... + + + +# include project implementation makefile +include nbproject/Makefile-impl.mk + +# include project make variables +include nbproject/Makefile-variables.mk diff --git a/funclist b/funclist new file mode 100644 index 0000000..ff3e876 --- /dev/null +++ b/funclist @@ -0,0 +1,48 @@ +_SYS_InterruptHigh: CODE, 8 0 114 +_configDescriptor1: SMALLCONST, 877 0 34 +_USB_CD_Ptr: SMALLCONST, 774 0 2 +_sd001: SMALLCONST, 776 0 52 +_APP_DeviceJoystickInitialize: CODE, 7568 0 36 +_USBCtrlTrfInHandler: CODE, 3704 0 260 +_USBTransferOnePacket: CODE, 3440 0 264 +_sd002: SMALLCONST, 911 0 28 +_USBStdGetDscHandler: CODE, 3138 0 302 +_memset: CODE, 7442 0 44 +_main: CODE, 7486 0 42 +_USER_USB_CALLBACK_EVENT_HANDLER: CODE, 6612 0 138 +_LED_Off: CODE, 7338 0 52 +_USBCtrlEPAllowDataStage: CODE, 6132 0 164 +_USBStdFeatureReqHandler: CODE, 962 0 932 +_BUTTON_IsPressed: CODE, 7180 0 54 +_BUTTON_Enable: CODE, 7604 0 36 +_USBCtrlEPAllowStatusStage: CODE, 5396 0 198 +_USBCtrlTrfSetupHandler: CODE, 5594 0 192 +_USBCtrlTrfOutHandler: CODE, 6750 0 98 +_USBCtrlEPServiceComplete: CODE, 3964 0 254 +_USBSuspend: CODE, 7234 0 52 +_memcpy: CODE, 7000 0 64 +__initialization: CODE, 7640 0 24 +_USBStdSetCfgHandler: CODE, 4722 0 248 +_USBStdGetStatusHandler: CODE, 5190 0 206 +_USBWakeFromSuspend: CODE, 7064 0 58 +_device_dsc: SMALLCONST, 939 0 18 +_USBCtrlTrfRxService: CODE, 2794 0 344 +_USBCtrlTrfTxService: CODE, 4970 0 220 +_USBEnableEndpoint: CODE, 6848 0 82 +_SYSTEM_Initialize: CODE, 7122 0 58 +_APP_LEDUpdateUSBStatus: CODE, 6456 0 156 +_USBConfigureEndpoint: CODE, 6296 0 160 +_USBDeviceInit: CODE, 2366 0 428 +_USBIncrement1msInternalTimers: CODE, 7528 0 40 +_USB_SD_Ptr: SMALLCONST, 768 0 6 +_hid_rpt01: SMALLCONST, 828 0 49 +_LED_On: CODE, 7390 0 52 +_sd000: SMALLCONST, 957 0 4 +_APP_DeviceJoystickTasks: CODE, 5786 0 178 +_LED_Enable: CODE, 7286 0 52 +_USBCtrlEPService: CODE, 5964 0 168 +_USBStallHandler: CODE, 6930 0 70 +_USBDeviceTasks: CODE, 1894 0 472 +_USBCheckHIDRequest: CODE, 4470 0 252 +_USBCheckStdRequest: CODE, 4218 0 252 +Total: 7009 \ No newline at end of file diff --git a/inc/drivers/adc.h b/inc/drivers/adc.h new file mode 100644 index 0000000..cc5d730 --- /dev/null +++ b/inc/drivers/adc.h @@ -0,0 +1,113 @@ +/******************************************************************** + Software License Agreement: + + The software supplied herewith by Microchip Technology Incorporated + (the "Company") for its PIC(R) Microcontroller is intended and + supplied to you, the Company's customer, for use solely and + exclusively on Microchip PIC Microcontroller products. The + software is owned by the Company and/or its supplier, and is + protected under applicable copyright laws. All rights are reserved. + Any use in violation of the foregoing restrictions may subject the + user to criminal sanctions under applicable laws, as well as to + civil liability for the breach of the terms and conditions of this + license. + + THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, + WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED + TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, + IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR + CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + *******************************************************************/ + +#ifndef ADC_H +#define ADC_H + +#include +#include + +/*** ADC Channel Definitions *****************************************/ +//#define ADC_CHANNEL_POTENTIOMETER ADC_CHANNEL_10 + +typedef enum { + ADC_CHANNEL_8 = 8, + ADC_CHANNEL_9 = 9 +} ADC_CHANNEL; + +typedef enum { + ADC_CONFIGURATION_DEFAULT +} ADC_CONFIGURATION; + +/********************************************************************* + * Function: ADC_ReadPercentage(ADC_CHANNEL channel); + * + * Overview: Reads the requested ADC channel and returns the percentage + * of that conversions result (0-100%). + * + * PreCondition: channel is enabled via ADC_Enable() + * + * Input: ADC_CHANNEL channel - enumeration of the ADC channels + * available in this demo. They should be meaningful names and + * not the names of the ADC pins on the device (as the demo code + * may be ported to other boards). + * i.e. ADC_ReadPercentage(ADC_CHANNEL_POTENTIOMETER); + * + * Output: uint8_t indicating the percentage of the result 0-100% or + * 0xFF for an error + * + ********************************************************************/ +uint8_t ADC_ReadPercentage(ADC_CHANNEL channel); + + +/********************************************************************* + * Function: ADC_Read10bit(ADC_CHANNEL channel); + * + * Overview: Reads the requested ADC channel and returns the 10-bit + * representation of this data. + * + * PreCondition: channel is enabled via ADC_Enable() + * + * Input: ADC_CHANNEL channel - enumeration of the ADC channels + * available in this demo. They should be meaningful names and + * not the names of the ADC pins on the device (as the demo code + * may be ported to other boards). + * i.e. - ADCReadPercentage(ADC_CHANNEL_POTENTIOMETER); + * + * Output: uint16_t the right adjusted 10-bit representation of the ADC + * channel conversion or 0xFFFF for an error. + * + ********************************************************************/ +uint16_t ADC_Read10bit(ADC_CHANNEL channel); + + +uint8_t ADC_Read8bit(ADC_CHANNEL channel); + +/********************************************************************* + * Function: bool ADC_Enable(ADC_CHANNEL channel, ADC_CONFIGURATION configuration); + * + * Overview: Enables specified channel + * + * PreCondition: none + * + * Input: ADC_CHANNEL channel - the channel to enable + * + * Output: bool - true if successfully configured. false otherwise. + * + ********************************************************************/ +bool ADC_Enable(ADC_CHANNEL channel); + +/********************************************************************* + * Function: bool ADC_SetConfiguration(ADC_CONFIGURATION configuration) + * + * Overview: Configures the ADC module to specified setting + * + * PreCondition: none + * + * Input: ADC_CONFIGURATION configuration - the mode in which to run the ADC + * + * Output: bool - true if successfully configured. false otherwise. + * + ********************************************************************/ +bool ADC_SetConfiguration(ADC_CONFIGURATION configuration); + +#endif //ADC_H diff --git a/inc/drivers/app_led_usb_status.h b/inc/drivers/app_led_usb_status.h new file mode 100644 index 0000000..f657173 --- /dev/null +++ b/inc/drivers/app_led_usb_status.h @@ -0,0 +1,37 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +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. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ + +/********************************************************************* +* Function: void APP_LEDUpdateUSBStatus(void); +* +* Overview: Uses one LED to indicate the status of the device on the USB bus. +* A fast blink indicates successfully connected. A slow pulse +* indicates that it is still in the process of connecting. Off +* indicates thta it is not attached to the bus or the bus is suspended. +* This should be called on every start of frame packet reception and +* if a suspend/resume event occurs. +* +* PreCondition: LEDs are enabled. +* +* Input: None +* +* Output: None +* +********************************************************************/ +void APP_LEDUpdateUSBStatus(void); diff --git a/inc/drivers/buttons.h b/inc/drivers/buttons.h new file mode 100644 index 0000000..a4f589e --- /dev/null +++ b/inc/drivers/buttons.h @@ -0,0 +1,72 @@ +/******************************************************************** + Software License Agreement: + + The software supplied herewith by Microchip Technology Incorporated + (the "Company") for its PIC(R) Microcontroller is intended and + supplied to you, the Company's customer, for use solely and + exclusively on Microchip PIC Microcontroller products. The + software is owned by the Company and/or its supplier, and is + protected under applicable copyright laws. All rights are reserved. + Any use in violation of the foregoing restrictions may subject the + user to criminal sanctions under applicable laws, as well as to + civil liability for the breach of the terms and conditions of this + license. + + THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, + WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED + TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, + IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR + CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + *******************************************************************/ + +#include + +#ifndef BUTTONS_H +#define BUTTONS_H + +/*** Button Definitions *********************************************/ +typedef enum +{ + BUTTON_NONE, + BUTTON_S1, + BUTTON_S2 +} BUTTON; + +/********************************************************************* +* Function: bool BUTTON_IsPressed(BUTTON button); +* +* Overview: Returns the current state of the requested button +* +* PreCondition: button configured via BUTTON_SetConfiguration() +* +* Input: BUTTON button - enumeration of the buttons available in +* this demo. They should be meaningful names and not the names +* of the buttons on the silkscreen on the board (as the demo +* code may be ported to other boards). +* i.e. - ButtonIsPressed(BUTTON_SEND_MESSAGE); +* +* Output: TRUE if pressed; FALSE if not pressed. +* +********************************************************************/ +bool BUTTON_IsPressed(BUTTON button); + +/********************************************************************* +* Function: void BUTTON_Enable(BUTTON button); +* +* Overview: Returns the current state of the requested button +* +* PreCondition: button configured via BUTTON_SetConfiguration() +* +* Input: BUTTON button - enumeration of the buttons available in +* this demo. They should be meaningful names and not the names +* of the buttons on the silkscreen on the board (as the demo +* code may be ported to other boards). +* i.e. - ButtonIsPressed(BUTTON_SEND_MESSAGE); +* +* Output: None +* +********************************************************************/ +void BUTTON_Enable(BUTTON button); + +#endif //BUTTONS_H diff --git a/inc/drivers/eeprom.h b/inc/drivers/eeprom.h new file mode 100644 index 0000000..ae6be15 --- /dev/null +++ b/inc/drivers/eeprom.h @@ -0,0 +1,38 @@ +/* + * EEPROM routines + * www.flitey.com + */ + +#ifndef EEPROM_H +#define EEPROM_H + +/** + * Gets the value in EEPROM at the specified address. + * @param byteAddress the address of the byte + * @return the value + */ +unsigned char EepromReadByte(uint8_t byteAddress); + +/** + * Sets the value in EEPROM with the specified value at the specified address. + * @param byteAddress the address location where the value will be stored + * @param byteData the value to store + */ +void EepromWriteByte(uint8_t byteAddress, uint8_t byteData); + +/** + * Gets two bytes from EEPROM starting at the specified address. + * @param startAddress the starting address location + * @return the two byte value + */ +uint16_t EepromReadTwoBytes(uint8_t startAddress); + +/** + * Sets the value in EEPROM with the specified value at the specified address + * @param startAddress the starting address location where the value will be stored + * @param value the value to store + */ +void EepromWriteTwoBytes(uint8_t startAddress, uint16_t value); + +#endif /* EEPROM_H */ + diff --git a/inc/drivers/joystick.h b/inc/drivers/joystick.h new file mode 100644 index 0000000..2c70a8c --- /dev/null +++ b/inc/drivers/joystick.h @@ -0,0 +1,35 @@ +/** + * Joystick functions + * www.flitey.com + */ + +#ifndef USBJOYSTICK_H +#define USBJOYSTICK_H +/** + * Initializes the joystick endpoint + */ +void JoystickInitialize(); + +/** + * Runs the calibration for the joystick potentiometers + */ +void JoystickRunCalibration(); + +/** + * Sets the calibration values to the specified values + * @param x_min the min value for the X axis + * @param x_mid the mid value for the X axis + * @param x_max the max value for the X axis + * @param y_min the min value for the Y axis + * @param y_mid the mid value for the Y axis + * @param y_max the max value for the Y axis + */ +void JoystickUseSavedCalibration(uint16_t x_min, uint16_t x_mid, uint16_t x_max, uint16_t y_min, uint16_t y_mid, uint16_t y_max); + +/** + * Perform the joystick tasks which includes getting the values from the joystick + * and then sending them to the computer. + */ +void JoystickTasks(); + +#endif /* USBJOYSTICK_H */ \ No newline at end of file diff --git a/inc/drivers/leds.h b/inc/drivers/leds.h new file mode 100644 index 0000000..97c8d8c --- /dev/null +++ b/inc/drivers/leds.h @@ -0,0 +1,129 @@ +/******************************************************************** + Software License Agreement: + + The software supplied herewith by Microchip Technology Incorporated + (the "Company") for its PIC(R) Microcontroller is intended and + supplied to you, the Company's customer, for use solely and + exclusively on Microchip PIC Microcontroller products. The + software is owned by the Company and/or its supplier, and is + protected under applicable copyright laws. All rights are reserved. + Any use in violation of the foregoing restrictions may subject the + user to criminal sanctions under applicable laws, as well as to + civil liability for the breach of the terms and conditions of this + license. + + THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, + WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED + TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, + IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR + CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + *******************************************************************/ + +#ifndef LEDS_H +#define LEDS_H + +#include + +/** Type defintions *********************************/ +typedef enum +{ + LED_NONE, + LED_D1, + LED_D2, + LED_D3, + LED_D4 +} LED; + +#define LED_COUNT 4 + +/********************************************************************* +* Function: void LED_On(LED led); +* +* Overview: Turns requested LED on +* +* PreCondition: LED configured via LED_Configure() +* +* Input: LED led - enumeration of the LEDs available in this +* demo. They should be meaningful names and not the names of +* the LEDs on the silkscreen on the board (as the demo code may +* be ported to other boards). +* i.e. - LED_On(LED_CONNECTION_DETECTED); +* +* Output: none +* +********************************************************************/ +void LED_On(LED led); + +/********************************************************************* +* Function: void LED_Off(LED led); +* +* Overview: Turns requested LED off +* +* PreCondition: LED configured via LEDConfigure() +* +* Input: LED led - enumeration of the LEDs available in this +* demo. They should be meaningful names and not the names of +* the LEDs on the silkscreen on the board (as the demo code may +* be ported to other boards). +* i.e. - LED_Off(LED_CONNECTION_DETECTED); +* +* Output: none +* +********************************************************************/ +void LED_Off(LED led); + +/********************************************************************* +* Function: void LED_Toggle(LED led); +* +* Overview: Toggles the state of the requested LED +* +* PreCondition: LED configured via LEDConfigure() +* +* Input: LED led - enumeration of the LEDs available in this +* demo. They should be meaningful names and not the names of +* the LEDs on the silkscreen on the board (as the demo code may +* be ported to other boards). +* i.e. - LED_Toggle(LED_CONNECTION_DETECTED); +* +* Output: none +* +********************************************************************/ +void LED_Toggle(LED led); + +/********************************************************************* +* Function: bool LED_Get(LED led); +* +* Overview: Returns the current state of the requested LED +* +* PreCondition: LED configured via LEDConfigure() +* +* Input: LED led - enumeration of the LEDs available in this +* demo. They should be meaningful names and not the names of +* the LEDs on the silkscreen on the board (as the demo code may +* be ported to other boards). +* i.e. - LED_Get(LED_CONNECTION_DETECTED); +* +* Output: true if on, false if off +* +********************************************************************/ +bool LED_Get(LED led); + +/********************************************************************* +* Function: bool LED_Enable(LED led); +* +* Overview: Configures the LED for use by the other LED API +* +* PreCondition: none +* +* Input: LED led - enumeration of the LEDs available in this +* demo. They should be meaningful names and not the names of +* the LEDs on the silkscreen on the board (as the demo code may +* be ported to other boards). +* +* Output: none +* +********************************************************************/ +void LED_Enable(LED led); + +#endif //LEDS_H diff --git a/inc/fixed_address_memory.h b/inc/fixed_address_memory.h new file mode 100644 index 0000000..cbd3660 --- /dev/null +++ b/inc/fixed_address_memory.h @@ -0,0 +1,28 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +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. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ + +#ifndef FIXED_MEMORY_ADDRESS_H +#define FIXED_MEMORY_ADDRESS_H + +#define FIXED_ADDRESS_MEMORY + +#define JOYSTICK_DATA_ADDRESS 0x260 +#define HID_CUSTOM_IN_DATA_BUFFER_ADDRESS 0x2A0 + +#endif //FIXED_MEMORY_ADDRESS \ No newline at end of file diff --git a/inc/io_mapping.h b/inc/io_mapping.h new file mode 100644 index 0000000..782d6f8 --- /dev/null +++ b/inc/io_mapping.h @@ -0,0 +1,29 @@ +/** + * Mapping of IO + */ + +#include "system.h" + +#define GAME_SWITCH_0 BUTTON_S1 +#define GAME_SWITCH_1 BUTTON_S2 + +#define PDL0 ADC_CHANNEL_8 +#define PDL1 ADC_CHANNEL_9 + +#define LED_USB_DEVICE_STATE LED_D1 + +#define X_AXIS_MIN_EEPROM_ADDRESS 0x00 +#define X_AXIS_MID_EEPROM_ADDRESS 0x02 +#define X_AXIS_MAX_EEPROM_ADDRESS 0x04 + +#define Y_AXIS_MIN_EEPROM_ADDRESS 0x06 +#define Y_AXIS_MID_EEPROM_ADDRESS 0x08 +#define Y_AXIS_MAX_EEPROM_ADDRESS 0x0A + +#define JOYSTICK_10_BIT_MAX 1023 +#define JOYSTICK_10_BIT_MID 511 +#define JOYSTICK_10_BIT_MIN 0 + +#define JOYSTICK_8_BIT_MAX_OUTPUT 255 +#define JOYSTICK_8_BIT_MID_OUTPUT 127 +#define JOYSTICK_8_BIT_MIN_OUTPUT 0 \ No newline at end of file diff --git a/inc/system.h b/inc/system.h new file mode 100644 index 0000000..a0f5a5b --- /dev/null +++ b/inc/system.h @@ -0,0 +1,27 @@ +/** + * System definitions and functions + */ + +#ifndef SYSTEM_H +#define SYSTEM_H + +#include +#include + +#include "buttons.h" +#include "leds.h" +#include "adc.h" + +#include "io_mapping.h" +#include "fixed_address_memory.h" + +/*** System States **************************************************/ +typedef enum { + SYSTEM_STATE_USB_START, + SYSTEM_STATE_USB_SUSPEND, + SYSTEM_STATE_USB_RESUME +} SYSTEM_STATE; + +void SYSTEM_Initialize(SYSTEM_STATE state); + +#endif diff --git a/inc/usb/usb.h b/inc/usb/usb.h new file mode 100644 index 0000000..a26ea9a --- /dev/null +++ b/inc/usb/usb.h @@ -0,0 +1,70 @@ +// DOM-IGNORE-BEGIN +/******************************************************************************* +Copyright 2015 Microchip Technology Inc. (www.microchip.com) + +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. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ +//DOM-IGNORE-END + + +/******************************************************************************* + Module for Microchip USB Library + + Company: + Microchip Technology Inc. + + File Name: + usb.h + + Summary: + This header file exposes the core library APIs and definitions for the USB + library. + + Description: + This header file exposes the core library APIs and definitions for the USB + library. The user is responsible for also including the header file for + the specific driver they will be using. +*******************************************************************************/ + +#ifndef _USB_H_ +#define _USB_H_ + +#include "usb_config.h" + +#include "usb_common.h" // Common USB library definitions +#include "usb_ch9.h" // USB device framework definitions + +#if defined( USB_SUPPORT_DEVICE ) + #include "usb_device.h" // USB Device abstraction layer interface +#endif + +#if defined( USB_SUPPORT_HOST ) + #include "usb_host.h" // USB Host abstraction layer interface +#endif + +#include "usb_hal.h" // Hardware Abstraction Layer interface + +/* USB Library version number. This can be used to verify in an application + specific version of the library is being used. + */ +#define USB_MAJOR_VER 2 // Firmware version, major release number. +#define USB_MINOR_VER 13 // Firmware version, minor release number. +#define USB_DOT_VER 0 // Firmware version, dot release number. + +#endif // _USB_H_ + + + diff --git a/inc/usb/usb_ch9.h b/inc/usb/usb_ch9.h new file mode 100644 index 0000000..97010f5 --- /dev/null +++ b/inc/usb/usb_ch9.h @@ -0,0 +1,596 @@ +// DOM-IGNORE-BEGIN +/******************************************************************************* +Copyright 2015 Microchip Technology Inc. (www.microchip.com) + +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. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ +//DOM-IGNORE-END + + +/******************************************************************************* + Module for Microchip USB Library + + Company: + Microchip Technology Inc. + + File Name: + usb_ch9.h + + Summary: + Defines types associated with chapter 9 of the USB specification. + + Description: + Defines types associated with chapter 9 of the USB specification. +*******************************************************************************/ + +#ifndef _USB_CH9_H_ +#define _USB_CH9_H_ + +#include + +#if defined(__XC8) + #define __attribute__(a) +#endif + +// ***************************************************************************** +// ***************************************************************************** +// Section: USB Descriptors +// ***************************************************************************** +// ***************************************************************************** + +#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor. +#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor. +#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor. +#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor. +#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor. +#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier. +#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration. +#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power. +#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor. + +// ***************************************************************************** +/* USB Device Descriptor Structure + +This struct defines the structure of a USB Device Descriptor. +*/ +typedef struct __attribute__ ((packed)) _USB_DEVICE_DESCRIPTOR +{ + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE). + uint16_t bcdUSB; // USB Spec Release Number (BCD). + uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0. + uint16_t idVendor; // Vendor ID (assigned by the USB-IF). + uint16_t idProduct; // Product ID (assigned by the manufacturer). + uint16_t bcdDevice; // Device release number (BCD). + uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer. + uint8_t iProduct; // Index of String Descriptor describing the product. + uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number. + uint8_t bNumConfigurations; // Number of possible configurations. +} USB_DEVICE_DESCRIPTOR; + + +// ***************************************************************************** +/* USB Configuration Descriptor Structure + +This struct defines the structure of a USB Configuration Descriptor. +*/ +typedef struct __attribute__ ((packed)) _USB_CONFIGURATION_DESCRIPTOR +{ + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). + uint16_t wTotalLength; // Total length of all descriptors for this configuration. + uint8_t bNumInterfaces; // Number of interfaces in this configuration. + uint8_t bConfigurationValue; // Value of this configuration (1 based). + uint8_t iConfiguration; // Index of String Descriptor describing the configuration. + uint8_t bmAttributes; // Configuration characteristics. + uint8_t bMaxPower; // Maximum power consumed by this configuration. +} USB_CONFIGURATION_DESCRIPTOR; + +// Attributes bits +#define USB_CFG_DSC_REQUIRED 0x80 // Required attribute +#define USB_CFG_DSC_SELF_PWR (0x40|USB_CFG_DSC_REQUIRED) // Device is self powered. +#define USB_CFG_DSC_REM_WAKE (0x20|USB_CFG_DSC_REQUIRED) // Device can request remote wakup + + +// ***************************************************************************** +/* USB Interface Descriptor Structure + +This struct defines the structure of a USB Interface Descriptor. +*/ +typedef struct __attribute__ ((packed)) _USB_INTERFACE_DESCRIPTOR +{ + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). + uint8_t bInterfaceNumber; // Number of this interface (0 based). + uint8_t bAlternateSetting; // Value of this alternate interface setting. + uint8_t bNumEndpoints; // Number of endpoints in this interface. + uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t iInterface; // Index of String Descriptor describing the interface. +} USB_INTERFACE_DESCRIPTOR; + + +// ***************************************************************************** +/* USB Endpoint Descriptor Structure + +This struct defines the structure of a USB Endpoint Descriptor. +*/ +typedef struct __attribute__ ((packed)) _USB_ENDPOINT_DESCRIPTOR +{ + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). + uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN). + uint8_t bmAttributes; // Endpoint transfer type. + uint16_t wMaxPacketSize; // Maximum packet size. + uint8_t bInterval; // Polling interval in frames. +} USB_ENDPOINT_DESCRIPTOR; + + +// Endpoint Direction +#define EP_DIR_IN 0x80 // Data flows from device to host +#define EP_DIR_OUT 0x00 // Data flows from host to device + + +// ****************************************************************** +// USB Endpoint Attributes +// ****************************************************************** + +// Section: Transfer Types +#define EP_ATTR_CONTROL (0<<0) // Endoint used for control transfers +#define EP_ATTR_ISOCH (1<<0) // Endpoint used for isochronous transfers +#define EP_ATTR_BULK (2<<0) // Endpoint used for bulk transfers +#define EP_ATTR_INTR (3<<0) // Endpoint used for interrupt transfers + +// Section: Synchronization Types (for isochronous endpoints) +#define EP_ATTR_NO_SYNC (0<<2) // No Synchronization +#define EP_ATTR_ASYNC (1<<2) // Asynchronous +#define EP_ATTR_ADAPT (2<<2) // Adaptive synchronization +#define EP_ATTR_SYNC (3<<2) // Synchronous + +// Section: Usage Types (for isochronous endpoints) +#define EP_ATTR_DATA (0<<4) // Data Endpoint +#define EP_ATTR_FEEDBACK (1<<4) // Feedback endpoint +#define EP_ATTR_IMP_FB (2<<4) // Implicit Feedback data EP + +// Section: Max Packet Sizes +#define EP_MAX_PKT_INTR_LS 8 // Max low-speed interrupt packet +#define EP_MAX_PKT_INTR_FS 64 // Max full-speed interrupt packet +#define EP_MAX_PKT_ISOCH_FS 1023 // Max full-speed isochronous packet +#define EP_MAX_PKT_BULK_FS 64 // Max full-speed bulk packet +#define EP_LG_PKT_BULK_FS 32 // Large full-speed bulk packet +#define EP_MED_PKT_BULK_FS 16 // Medium full-speed bulk packet +#define EP_SM_PKT_BULK_FS 8 // Small full-speed bulk packet + +/* Descriptor IDs +The descriptor ID type defines the information required by the HOST during a +GET_DESCRIPTOR request +*/ +typedef struct +{ + uint8_t index; + uint8_t type; + uint16_t language_id; + +} DESCRIPTOR_ID; + +// ***************************************************************************** +/* USB OTG Descriptor Structure + +This struct defines the structure of a USB OTG Descriptor. Note that this +structure may need to be packed, or even accessed as uint8_ts, to properly access +the correct fields when used on some device architectures. +*/ +typedef struct __attribute__ ((packed)) _USB_OTG_DESCRIPTOR +{ + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // OTG descriptor type (USB_DESCRIPTOR_OTG). + uint8_t bmAttributes; // OTG attributes. +} USB_OTG_DESCRIPTOR; + + +// ****************************************************************** +// Section: USB String Descriptor Structure +// ****************************************************************** +// This structure describes the USB string descriptor. The string +// descriptor provides user-readable information about various aspects of +// the device. The first string descriptor (string descriptor zero (0)), +// provides a list of the number of languages supported by the set of +// string descriptors for this device instead of an actual string. +// +// Note: The strings are in 2-uint8_t-per-character unicode, not ASCII. +// +// Note: This structure only describes the "header" of the string +// descriptor. The actual data (either the language ID array or the +// array of unicode characters making up the string, must be allocated +// immediately following this header with no padding between them. + +typedef struct __attribute__ ((packed)) _USB_STRING_DSC +{ + uint8_t bLength; // Size of this descriptor + uint8_t bDescriptorType; // Type, USB_DSC_STRING + +} USB_STRING_DESCRIPTOR; + + +// ****************************************************************** +// Section: USB Device Qualifier Descriptor Structure +// ****************************************************************** +// This structure describes the device qualifier descriptor. The device +// qualifier descriptor provides overall device information if the device +// supports "other" speeds. +// +// Note: A high-speed device may support "other" speeds (ie. full or low). +// If so, it may need to implement the the device qualifier and other +// speed descriptors. + +typedef struct __attribute__ ((packed)) _USB_DEVICE_QUALIFIER_DESCRIPTOR +{ + uint8_t bLength; // Size of this descriptor + uint8_t bType; // Type, always USB_DESCRIPTOR_DEVICE_QUALIFIER + uint16_t bcdUSB; // USB spec version, in BCD + uint8_t bDeviceClass; // Device class code + uint8_t bDeviceSubClass; // Device sub-class code + uint8_t bDeviceProtocol; // Device protocol + uint8_t bMaxPacketSize0; // EP0, max packet size + uint8_t bNumConfigurations; // Number of "other-speed" configurations + uint8_t bReserved; // Always zero (0) + +} USB_DEVICE_QUALIFIER_DESCRIPTOR; + +// ****************************************************************** +// Section: USB Setup Packet Structure +// ****************************************************************** +// This structure describes the data contained in a USB standard device +// request setup packet. It is the data packet sent from the host to +// the device to control and configure the device. +// +// Note: Refer to the USB 2.0 specification for additional details on the +// usage of the setup packet and standard device requests. +typedef union __attribute__ ((packed)) +{ + /** Standard Device Requests ***********************************/ + struct __attribute__ ((packed)) + { + uint8_t bmRequestType; //from table 9-2 of USB2.0 spec + uint8_t bRequest; //from table 9-2 of USB2.0 spec + uint16_t wValue; //from table 9-2 of USB2.0 spec + uint16_t wIndex; //from table 9-2 of USB2.0 spec + uint16_t wLength; //from table 9-2 of USB2.0 spec + }; + struct __attribute__ ((packed)) + { + unsigned :8; + unsigned :8; + union + { + uint16_t Val; + uint8_t v[2]; + struct + { + uint8_t LB; + uint8_t HB; + } byte; + } W_Value; + + union + { + uint16_t Val; + uint8_t v[2]; + struct + { + uint8_t LB; + uint8_t HB; + } byte; + } W_Index; + + union + { + uint16_t Val; + uint8_t v[2]; + struct + { + uint8_t LB; + uint8_t HB; + } byte; + } W_Length; + }; + struct __attribute__ ((packed)) + { + unsigned Recipient:5; //Device,Interface,Endpoint,Other + unsigned RequestType:2; //Standard,Class,Vendor,Reserved + unsigned DataDir:1; //Host-to-device,Device-to-host + unsigned :8; + uint8_t bFeature; //DEVICE_REMOTE_WAKEUP,ENDPOINT_HALT + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + }; + struct __attribute__ ((packed)) + { + union // offset description + { // ------ ------------------------ + uint8_t bmRequestType; // 0 Bit-map of request type + struct + { + uint8_t recipient: 5; // Recipient of the request + uint8_t type: 2; // Type of request + uint8_t direction: 1; // Direction of data X-fer + }; + }requestInfo; + }; + struct __attribute__ ((packed)) + { + unsigned :8; + unsigned :8; + uint8_t bDscIndex; //For Configuration and String DSC Only + uint8_t bDescriptorType; //Device,Configuration,String + uint16_t wLangID; //Language ID + unsigned :8; + unsigned :8; + }; + struct __attribute__ ((packed)) + { + unsigned :8; + unsigned :8; + uint8_t bDevADR; //Device Address 0-127 + uint8_t bDevADRH; //Must equal zero + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + }; + struct __attribute__ ((packed)) + { + unsigned :8; + unsigned :8; + uint8_t bConfigurationValue; //Configuration Value 0-255 + uint8_t bCfgRSD; //Must equal zero (Reserved) + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + }; + struct __attribute__ ((packed)) + { + unsigned :8; + unsigned :8; + uint8_t bAltID; //Alternate Setting Value 0-255 + uint8_t bAltID_H; //Must equal zero + uint8_t bIntfID; //Interface Number Value 0-255 + uint8_t bIntfID_H; //Must equal zero + unsigned :8; + unsigned :8; + }; + struct __attribute__ ((packed)) + { + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + uint8_t bEPID; //Endpoint ID (Number & Direction) + uint8_t bEPID_H; //Must equal zero + unsigned :8; + unsigned :8; + }; + struct __attribute__ ((packed)) + { + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + unsigned EPNum:4; //Endpoint Number 0-15 + unsigned :3; + unsigned EPDir:1; //Endpoint Direction: 0-OUT, 1-IN + unsigned :8; + unsigned :8; + unsigned :8; + }; + + /** End: Standard Device Requests ******************************/ + +} CTRL_TRF_SETUP, SETUP_PKT, *PSETUP_PKT; + + +// ****************************************************************** +// ****************************************************************** +// Section: USB Specification Constants +// ****************************************************************** +// ****************************************************************** + +// Section: Valid PID Values +//DOM-IGNORE-BEGIN +#define PID_OUT 0x1 // PID for an OUT token +#define PID_ACK 0x2 // PID for an ACK handshake +#define PID_DATA0 0x3 // PID for DATA0 data +#define PID_PING 0x4 // Special PID PING +#define PID_SOF 0x5 // PID for a SOF token +#define PID_NYET 0x6 // PID for a NYET handshake +#define PID_DATA2 0x7 // PID for DATA2 data +#define PID_SPLIT 0x8 // Special PID SPLIT +#define PID_IN 0x9 // PID for a IN token +#define PID_NAK 0xA // PID for a NAK handshake +#define PID_DATA1 0xB // PID for DATA1 data +#define PID_PRE 0xC // Special PID PRE (Same as PID_ERR) +#define PID_ERR 0xC // Special PID ERR (Same as PID_PRE) +#define PID_SETUP 0xD // PID for a SETUP token +#define PID_STALL 0xE // PID for a STALL handshake +#define PID_MDATA 0xF // PID for MDATA data + +#define PID_MASK_DATA 0x03 // Data PID mask +#define PID_MASK_DATA_SHIFTED (PID_MASK_DATA << 2) // Data PID shift to proper position +//DOM-IGNORE-END + +// Section: USB Token Types +//DOM-IGNORE-BEGIN +#define USB_TOKEN_OUT 0x01 // U1TOK - OUT token +#define USB_TOKEN_IN 0x09 // U1TOK - IN token +#define USB_TOKEN_SETUP 0x0D // U1TOK - SETUP token +//DOM-IGNORE-END + +// Section: OTG Descriptor Constants + +#define OTG_HNP_SUPPORT 0x02 // OTG Descriptor bmAttributes - HNP support flag +#define OTG_SRP_SUPPORT 0x01 // OTG Descriptor bmAttributes - SRP support flag + +// Section: Endpoint Directions + +#define USB_IN_EP 0x80 // IN endpoint mask +#define USB_OUT_EP 0x00 // OUT endpoint mask + +// Section: Standard Device Requests + +#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS +#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE +#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE +#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS +#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR +#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR +#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION +#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION +#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE +#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE +#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME + +#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt +#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up +#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode + +// Section: Setup Data Constants + +#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer +#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer +#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard +#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class +#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor +#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device +#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface +#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint +#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other + +#define USB_SETUP_HOST_TO_DEVICE_BITFIELD (USB_SETUP_HOST_TO_DEVICE>>7) // Device Request bmRequestType transfer direction - host to device transfer - bit definition +#define USB_SETUP_DEVICE_TO_HOST_BITFIELD (USB_SETUP_DEVICE_TO_HOST>>7) // Device Request bmRequestType transfer direction - device to host transfer - bit definition +#define USB_SETUP_TYPE_STANDARD_BITFIELD (USB_SETUP_TYPE_STANDARD>>5) // Device Request bmRequestType type - standard +#define USB_SETUP_TYPE_CLASS_BITFIELD (USB_SETUP_TYPE_CLASS>>5) // Device Request bmRequestType type - class +#define USB_SETUP_TYPE_VENDOR_BITFIELD (USB_SETUP_TYPE_VENDOR>>5) // Device Request bmRequestType type - vendor +#define USB_SETUP_RECIPIENT_DEVICE_BITFIELD (USB_SETUP_RECIPIENT_DEVICE) // Device Request bmRequestType recipient - device +#define USB_SETUP_RECIPIENT_INTERFACE_BITFIELD (USB_SETUP_RECIPIENT_INTERFACE) // Device Request bmRequestType recipient - interface +#define USB_SETUP_RECIPIENT_ENDPOINT_BITFIELD (USB_SETUP_RECIPIENT_ENDPOINT) // Device Request bmRequestType recipient - endpoint +#define USB_SETUP_RECIPIENT_OTHER_BITFIELD (USB_SETUP_RECIPIENT_OTHER) // Device Request bmRequestType recipient - other + +// Section: OTG SET FEATURE Constants + +#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP +#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP +#define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP + +// Section: USB Endpoint Transfer Types + +#define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint. +#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint. +#define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint. +#define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint. + +// Section: Standard Feature Selectors for CLEAR_FEATURE Requests +#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient +#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient +#define USB_FEATURE_TEST_MODE 2 // Device recipient + + +// Section: USB Class Code Definitions +#define USB_HUB_CLASSCODE 0x09 // Class code for a hub. + +/******************************************************************** +USB Endpoint Definitions +USB Standard EP Address Format: DIR:X:X:X:EP3:EP2:EP1:EP0 +This is used in the descriptors. +********************************************************************/ +#define _EP_IN 0x80 +#define _EP_OUT 0x00 +#define _EP01_OUT 0x01 +#define _EP01_IN 0x81 +#define _EP02_OUT 0x02 +#define _EP02_IN 0x82 +#define _EP03_OUT 0x03 +#define _EP03_IN 0x83 +#define _EP04_OUT 0x04 +#define _EP04_IN 0x84 +#define _EP05_OUT 0x05 +#define _EP05_IN 0x85 +#define _EP06_OUT 0x06 +#define _EP06_IN 0x86 +#define _EP07_OUT 0x07 +#define _EP07_IN 0x87 +#define _EP08_OUT 0x08 +#define _EP08_IN 0x88 +#define _EP09_OUT 0x09 +#define _EP09_IN 0x89 +#define _EP10_OUT 0x0A +#define _EP10_IN 0x8A +#define _EP11_OUT 0x0B +#define _EP11_IN 0x8B +#define _EP12_OUT 0x0C +#define _EP12_IN 0x8C +#define _EP13_OUT 0x0D +#define _EP13_IN 0x8D +#define _EP14_OUT 0x0E +#define _EP14_IN 0x8E +#define _EP15_OUT 0x0F +#define _EP15_IN 0x8F + +/* Configuration Attributes */ +#define _DEFAULT (0x01<<7) //Default Value (Bit 7 is set) +#define _SELF (0x01<<6) //Self-powered (Supports if set) +#define _RWU (0x01<<5) //Remote Wakeup (Supports if set) +#define _HNP (0x01 << 1) //HNP (Supports if set) +#define _SRP (0x01) //SRP (Supports if set) + +/* Endpoint Transfer Type */ +#define _CTRL 0x00 //Control Transfer +#define _ISO 0x01 //Isochronous Transfer +#define _BULK 0x02 //Bulk Transfer + +#define _INTERRUPT 0x03 //Interrupt Transfer +#if defined(__18CXX) || defined(__C30__) || defined __XC16__ || defined(__XC8) + #define _INT 0x03 //Interrupt Transfer +#endif + +/* Isochronous Endpoint Synchronization Type */ +#define _NS (0x00<<2) //No Synchronization +#define _AS (0x01<<2) //Asynchronous +#define _AD (0x02<<2) //Adaptive +#define _SY (0x03<<2) //Synchronous + +/* Isochronous Endpoint Usage Type */ +#define _DE (0x00<<4) //Data endpoint +#define _FE (0x01<<4) //Feedback endpoint +#define _IE (0x02<<4) //Implicit feedback Data endpoint + +//These are the directional indicators used for the USBTransferOnePacket() +// function. +#define OUT_FROM_HOST 0 +#define IN_TO_HOST 1 + +#endif // _USB_CH9_H_ +/************************************************************************* + * EOF + */ + diff --git a/inc/usb/usb_common.h b/inc/usb/usb_common.h new file mode 100644 index 0000000..755c4a7 --- /dev/null +++ b/inc/usb/usb_common.h @@ -0,0 +1,474 @@ +// DOM-IGNORE-BEGIN +/******************************************************************************* +Copyright 2015 Microchip Technology Inc. (www.microchip.com) + +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. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ +//DOM-IGNORE-END + + +/******************************************************************************* + Module for Microchip USB Library + + Company: + Microchip Technology Inc. + + File Name: + usb_common.h + + Summary: + Defines types associated with both the USB host and USB device stacks but + not defined by the USB specification. + + Description: + Defines types associated with both the USB host and USB device stacks but + not defined by the USB specification. +*******************************************************************************/ + +//DOM-IGNORE-BEGIN +#ifndef _USB_COMMON_H_ +#define _USB_COMMON_H_ +//DOM-IGNORE-END + +#include +#include +#include + +// ***************************************************************************** +// ***************************************************************************** +// Section: USB Constants +// ***************************************************************************** +// ***************************************************************************** + +// Section: Error Code Values + +#define USB_SUCCESS 0x00 // USB operation successful. +#define USB_INVALID_STATE 0x01 // Operation cannot be performed in current state. +#define USB_BUSY 0x02 // A transaction is already in progress. +#define USB_ILLEGAL_REQUEST 0x03 // Cannot perform requested operation. +#define USB_INVALID_CONFIGURATION 0x04 // Configuration descriptor not found. +#define USB_MEMORY_ALLOCATION_ERROR 0x05 // Out of dynamic memory. +#define USB_UNKNOWN_DEVICE 0x06 // Device with specified address is not attached. +#define USB_CANNOT_ENUMERATE 0x07 // Cannot enumerate the attached device. +#define USB_EVENT_QUEUE_FULL 0x08 // Event queue was full when an event occured. +#define USB_ENDPOINT_BUSY 0x10 // Endpoint is currently processing a transaction. +#define USB_ENDPOINT_STALLED 0x11 // Endpoint is currently stalled. User must clear the condition. +#define USB_ENDPOINT_ERROR 0x12 // Will need more than this eventually +#define USB_ENDPOINT_ERROR_ILLEGAL_PID 0x13 // Illegal PID received. +#define USB_ENDPOINT_NOT_FOUND 0x14 // Requested endpoint does not exist on device. +#define USB_ENDPOINT_ILLEGAL_DIRECTION 0x15 // Reads must be performe on IN endpoints, writes on OUT endpoints. +//#define USB_ENDPOINT_TRANSACTION_IN_PROGRESS 0x16 +#define USB_ENDPOINT_NAK_TIMEOUT 0x17 // Too many NAK's occurred while waiting for the current transaction. +#define USB_ENDPOINT_ILLEGAL_TYPE 0x18 // Transfer type must match endpoint description. +#define USB_ENDPOINT_UNRESOLVED_STATE 0x19 // Endpoint is in an unknown state after completing a transaction. +#define USB_ENDPOINT_ERROR_BIT_STUFF 0x20 // USB Module - Bit stuff error. +#define USB_ENDPOINT_ERROR_DMA 0x21 // USB Module - DMA error. +#define USB_ENDPOINT_ERROR_TIMEOUT 0x22 // USB Module - Bus timeout. +#define USB_ENDPOINT_ERROR_DATA_FIELD 0x23 // USB Module - Data field size error. +#define USB_ENDPOINT_ERROR_CRC16 0x24 // USB Module - CRC16 failure. +#define USB_ENDPOINT_ERROR_END_OF_FRAME 0x25 // USB Module - End of Frame error. +#define USB_ENDPOINT_ERROR_PID_CHECK 0x26 // USB Module - Illegal PID received. +#define USB_ENDPOINT_ERROR_BMX 0x27 // USB Module - Bus Matrix error. +#define USB_ERROR_INSUFFICIENT_POWER 0x28 // Too much power was requested + +// Section: Return values for USBHostDeviceStatus() + +#define USB_DEVICE_STATUS 0x30 // Offset for USBHostDeviceStatus() return codes +#define USB_DEVICE_ATTACHED (USB_DEVICE_STATUS | 0x30) // Device is attached and running +#define USB_DEVICE_DETACHED (USB_DEVICE_STATUS | 0x01) // No device is attached +#define USB_DEVICE_ENUMERATING (USB_DEVICE_STATUS | 0x02) // Device is enumerating +#define USB_HOLDING_OUT_OF_MEMORY (USB_DEVICE_STATUS | 0x03) // Not enough heap space available +#define USB_HOLDING_UNSUPPORTED_DEVICE (USB_DEVICE_STATUS | 0x04) // Invalid configuration or unsupported class +#define USB_HOLDING_UNSUPPORTED_HUB (USB_DEVICE_STATUS | 0x05) // Hubs are not supported +#define USB_HOLDING_INVALID_CONFIGURATION (USB_DEVICE_STATUS | 0x06) // Invalid configuration requested +#define USB_HOLDING_PROCESSING_CAPACITY (USB_DEVICE_STATUS | 0x07) // Processing requirement excessive +#define USB_HOLDING_POWER_REQUIREMENT (USB_DEVICE_STATUS | 0x08) // Power requirement excessive +#define USB_HOLDING_CLIENT_INIT_ERROR (USB_DEVICE_STATUS | 0x09) // Client driver failed to initialize +#define USB_DEVICE_SUSPENDED (USB_DEVICE_STATUS | 0x0A) // Device is suspended + +#define USB_ERROR_CLASS_DEFINED 0x50 // Offset for application defined errors + +#define USB_SINGLE_DEVICE_ADDRESS 0x01 // Default USB device address (single device support) + + +// ***************************************************************************** +// ***************************************************************************** +// Section: USB Data Types +// ***************************************************************************** +// ***************************************************************************** + +// ***************************************************************************** +/* Data Transfer Flags + +The following flags are used in the flags parameter of the "USBDEVTransferData" +and "USBHALTransferData" routines. They can be accessed by the bitfield +definitions or the macros can be OR'd together to identify the endpoint number +and properties of the data transfer. + + + 7 6 5 4 3 2 1 0 - Field name + | | | | \_____/ + | | | | +----- ep_num - Endpoint number + | | | +---------- zero_pkt - End transfer with short or zero-sized packet + | | +------------ dts - 0=DATA0 packet, 1=DATA1 packet + | +-------------- force_dts - Force data toggle sync to match dts field + +---------------- direction - Transfer direction: 0=Receive, 1=Transmit + +*/ + +typedef union +{ + uint8_t bitmap; + struct + { + uint8_t ep_num: 4; + uint8_t zero_pkt: 1; + uint8_t dts: 1; + uint8_t force_dts: 1; + uint8_t direction: 1; + }field; + +} TRANSFER_FLAGS; + +// ***************************************************************************** +/* Data Transfer Flags, Endpoint Number Constants + +These macros can be used as values for the "ep_num" field of the TRANSFER_FLAGS +data type. +*/ +#define USB_EP0 0 // +#define USB_EP1 1 // +#define USB_EP2 2 // +#define USB_EP3 3 // +#define USB_EP4 4 // +#define USB_EP5 5 // +#define USB_EP6 6 // +#define USB_EP7 7 // +#define USB_EP8 8 // +#define USB_EP9 9 // +#define USB_EP10 10 // +#define USB_EP11 11 // +#define USB_EP12 12 // +#define USB_EP13 13 // +#define USB_EP14 14 // +#define USB_EP15 15 // + +// ***************************************************************************** +/* Data Transfer Flags, Bitmap Constants + +These macros can be used as values for the "bitmap" field of the TRANSFER_FLAGS +data type. +*/ +#define USB_TRANSMIT 0x80 // Data will be transmitted to the USB +#define USB_RECEIVE 0x00 // Data will be received from the USB +#define USB_FORCE_DTS 0x40 // Forces data toggle sync as below: +#define USB_DTS_MASK 0x20 // Mask for DTS bit (below) +#define USB_ZERO_PKT 0x10 // End transfer w/a short or zero-length packet +#define USB_DATA0 0x00|USB_FORCE_DTS // Force DATA0 +#define USB_DATA1 0x20|USB_FORCE_DTS // Force DATA1 +#define USB_SETUP_PKT USB_RECEIVE|USB_DATA0|USB_EP0 // Setup Packet +#define USB_SETUP_DATA USB_DATA1|USB_ZERO_PKT|USB_EP0 // Setup-transfer Data Packet +#define USB_SETUP_STATUS USB_DATA1|USB_EP0 // Setup-transfer Status Packet +#define USB_EP_NUM_MASK 0x0F // Endpoint number (ep_num) mask + +// ***************************************************************************** +/* Data Transfer Flags, Initialization Macro + +This macro can be used with the above bitmap constants to initialize a +TRANSFER_FLAGS value. It provides the correct data type to avoid compiler +warnings. +*/ +#define XFLAGS(f) ((TRANSFER_FLAGS)((uint8_t)(f))) // Initialization Macro + + +// ***************************************************************************** +/* USB Events + +This enumeration identifies USB events that occur. It is used to +inform USB drivers and applications of events on the bus. It is passed +as a parameter to the event-handling routine, which must match the +prototype of the USB_CLIENT_EVENT_HANDLER data type, when an event occurs. +*/ + +typedef enum +{ + // No event occured (NULL event) + EVENT_NONE = 0, + + EVENT_DEVICE_STACK_BASE = 1, + + EVENT_HOST_STACK_BASE = 100, + + // A USB hub has been attached. Hub support is not currently available. + EVENT_HUB_ATTACH, + + // A stall has occurred. This event is not used by the Host stack. + EVENT_STALL, + + // VBus SRP Pulse, (VBus > 2.0v), Data: uint8_t Port Number (For future support) + EVENT_VBUS_SES_REQUEST, + + // The voltage on Vbus has dropped below 4.4V/4.7V. The application is + // responsible for monitoring Vbus and calling USBHostVbusEvent() with this + // event. This event is not generated by the stack. + EVENT_VBUS_OVERCURRENT, + + // An enumerating device is requesting power. The data associated with this + // event is of the data type USB_VBUS_POWER_EVENT_DATA. Note that + // the requested current is specified in 2mA units, identical to the power + // specification in a device's Configuration Descriptor. + EVENT_VBUS_REQUEST_POWER, + + // Release power from a detaching device. The data associated with this + // event is of the data type USB_VBUS_POWER_EVENT_DATA. The current value + // specified in the data can be ignored. + EVENT_VBUS_RELEASE_POWER, + + // The voltage on Vbus is good, and the USB OTG module can be powered on. + // The application is responsible for monitoring Vbus and calling + // USBHostVbusEvent() with this event. This event is not generated by the + // stack. If the application issues an EVENT_VBUS_OVERCURRENT, then no + // power will be applied to that port, and no device can attach to that + // port, until the application issues the EVENT_VBUS_POWER_AVAILABLE for + // the port. + EVENT_VBUS_POWER_AVAILABLE, + + // The attached device is not supported by the application. The attached + // device is not allowed to enumerate. + EVENT_UNSUPPORTED_DEVICE, + + // Cannot enumerate the attached device. This is generated if communication + // errors prevent the device from enumerating. + EVENT_CANNOT_ENUMERATE, + + // The client driver cannot initialize the the attached device. The + // attached is not allowed to enumerate. + EVENT_CLIENT_INIT_ERROR, + + // The Host stack does not have enough heap space to enumerate the device. + // Check the amount of heap space allocated to the application. In MPLAB, + // select Project> Build Options...> Project. Select the appropriate + // linker tab, and inspect the "Heap size" entry. + EVENT_OUT_OF_MEMORY, + + // Unspecified host error. (This error should not occur). + EVENT_UNSPECIFIED_ERROR, + + // USB cable has been detached. The data associated with this event is the + // address of detached device, a single uint8_t. + EVENT_DETACH, + + // A USB transfer has completed. The data associated with this event is of + // the data type HOST_TRANSFER_DATA if the event is generated from the host + // stack. + EVENT_TRANSFER, + + // A USB Start of Frame token has been received. This event is not + // used by the Host stack. + EVENT_SOF, + + // Device-mode resume received. This event is not used by the Host stack. + EVENT_RESUME, + + // Device-mode suspend/idle event received. This event is not used by the + // Host stack. + EVENT_SUSPEND, + + // Device-mode bus reset received. This event is not used by the Host + // stack. + EVENT_RESET, + + // In Host mode, an isochronous data read has completed. This event will only + // be passed to the DataEventHandler, which is only utilized if it is defined. + // Note that the DataEventHandler is called from within the USB interrupt, so + // it is critical that it return in time for the next isochronous data packet. + EVENT_DATA_ISOC_READ, + + // In Host mode, an isochronous data write has completed. This event will only + // be passed to the DataEventHandler, which is only utilized if it is defined. + // Note that the DataEventHandler is called from within the USB interrupt, so + // it is critical that it return in time for the next isochronous data packet. + EVENT_DATA_ISOC_WRITE, + + // In Host mode, this event gives the application layer the option to reject + // a client driver that was selected by the stack. This is needed when multiple + // devices are supported by class level support, but one configuration and client + // driver is preferred over another. Since configuration number is not guaranteed, + // the stack cannot do this automatically. This event is issued only when + // looking through configuration descriptors; the driver selected at the device + // level cannot be overridden, since there shouldn't be any other options to + // choose from. + EVENT_OVERRIDE_CLIENT_DRIVER_SELECTION, + + // In host mode, this event is thrown for every millisecond that passes. Like all + // events, this is thrown from the USBHostTasks() or USBTasks() routine so its + // timeliness will be determined by the rate that these functions are called. If + // they are not called very often, then the 1ms events will build up and be + // dispatched as the USBTasks() or USBHostTasks() functions are called (one event + // per call to these functions. + EVENT_1MS, + + // In device mode, this event is thrown when we receive a Set Interface request from + // the host. The stack will automatically handle the interface switch, but the app + // may need to know about the interface switch for performing tasks such as powering + // up/down audio hardware. + EVENT_ALT_INTERFACE, + + // If the application layer must do things to the device before the device is + // configured, they should be done at this point. The application layer should + // return true to hold the USB state machine at this point, while any USB or other + // processing continues. When the USB state machine can safely proceed, the application + // layer should return FALSE. + EVENT_HOLD_BEFORE_CONFIGURATION, + + // Class-defined event offsets start here: + EVENT_GENERIC_BASE = 400, // Offset for Generic class events + + EVENT_MSD_BASE = 500, // Offset for Mass Storage Device class events + + EVENT_HID_BASE = 600, // Offset for Human Interface Device class events + + EVENT_PRINTER_BASE = 700, // Offset for Printer class events + + EVENT_CDC_BASE = 800, // Offset for CDC class events + + EVENT_CHARGER_BASE = 900, // Offset for Charger client driver events. + + EVENT_AUDIO_BASE = 1000, // Offset for Audio client driver events. + + EVENT_USER_BASE = 10000, // Add integral values to this event number + // to create user-defined events. + + // There was a transfer error on the USB. The data associated with this + // event is of data type HOST_TRANSFER_DATA. + EVENT_BUS_ERROR = INT_MAX + +} USB_EVENT; + + +// ***************************************************************************** +/* EVENT_TRANSFER Data + +This data structure is passed to the appropriate layer's +USB_EVENT_HANDLER when an EVT_XFER event has occurred, indicating +that a transfer has completed on the USB. It provides the endpoint, +direction, and actual size of the transfer. + */ + +typedef struct _transfer_event_data +{ + TRANSFER_FLAGS flags; // Transfer flags (see above) + uint32_t size; // Actual number of bytes transferred + uint8_t pid; // Packet ID + +} USB_TRANSFER_EVENT_DATA; + + +// ***************************************************************************** +/* EVENT_VBUS_REQUEST_POWER and EVENT_VBUS_RELEASE_POWER Data + +This data structure is passed to the appropriate layer's +USB_EVENT_HANDLER when an EVENT_VBUS_REQUEST_POWER or EVENT_VBUS_RELEASE_POWER +event has occurred, indicating that a change in Vbus power is being requested. +*/ + +typedef struct _vbus_power_data +{ + uint8_t port; // Physical port number + uint8_t current; // Current in 2mA units +} USB_VBUS_POWER_EVENT_DATA; + + +// ***************************************************************************** +/* USB_OVERRIDE_CLIENT_DRIVER_EVENT_DATA Data + +This data structure is passed to the application layer when a client driver is +select, in case multiple client drivers can support a particular device. +*/ +typedef struct _override_client_driver_data +{ + uint16_t idVendor; + uint16_t idProduct; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; +} USB_OVERRIDE_CLIENT_DRIVER_EVENT_DATA; + + +// ***************************************************************************** +/* EVT_STALL Data + +The EVT_STALL event has a 16-bit data value associated with it where +a bit is set in the position for each endpoint that is currently +stalled (ie. bit 0 = EP0, bit 1 = EP1, etc.) +*/ + + +// ***************************************************************************** +// ***************************************************************************** +// Section: Event Handling Routines +// ***************************************************************************** +// ***************************************************************************** + +/******************************************************************************* + Function: + bool ( USB_EVENT event, + void *data, unsigned int size ) + + Description: + This routine is a "call out" routine that must be implemented by + any layer of the USB SW Stack (except the HAL which is at the + root of the event-call tree that needs to receive events. When + an event occurs, the HAL calls the next higher layer in the + stack to handle the event. Each layer either handles the event + or calls the layer above it to handle the event. Events are + identified by the "event" parameter and may have associated + data. If the higher layer was able to handle the event, it + should return true. If not, it should return false. + + Preconditions: + USBInitialize must have been called to initialize the USB SW + Stack. + + Parameters: + USB_EVENT event - Identifies the bus event that occurred + void *data - Pointer to event-specific data + unsigned int size - Size of the event-specific data + + Return Values: + None + + Remarks: + The function is name is defined by the layer that implements + it. A pointer to the function will be placed by into a table + that the lower-layer will use to call it. This requires the + function to use a specific call "signature" (return data type + and values and data parameter types and values). + +*******************************************************************************/ + +typedef bool (*USB_EVENT_HANDLER) ( USB_EVENT event, void *data, unsigned int size ); + +#define USB_PING_PONG__NO_PING_PONG 0x00 //0b00 +#define USB_PING_PONG__EP0_OUT_ONLY 0x01 //0b01 +#define USB_PING_PONG__FULL_PING_PONG 0x02 //0b10 +#define USB_PING_PONG__ALL_BUT_EP0 0x03 //0b11 + +#endif // _USB_COMMON_H_ +/************************************************************************* + * EOF + */ + diff --git a/inc/usb/usb_config.h b/inc/usb/usb_config.h new file mode 100644 index 0000000..7fb66fb --- /dev/null +++ b/inc/usb/usb_config.h @@ -0,0 +1,174 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +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. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ + +/********************************************************************* + * Descriptor specific type definitions are defined in: usbd.h + ********************************************************************/ + +#ifndef USBCFG_H +#define USBCFG_H + +#include + +/** DEFINITIONS ****************************************************/ +#define USB_EP0_BUFF_SIZE 8 // Valid Options: 8, 16, 32, or 64 bytes. + // Using larger options take more SRAM, but + // does not provide much advantage in most types + // of applications. Exceptions to this, are applications + // that use EP0 IN or OUT for sending large amounts of + // application related data. + +#define USB_MAX_NUM_INT 1 //Set this number to match the maximum interface number used in the descriptors for this firmware project +#define USB_MAX_EP_NUMBER 1 //Set this number to match the maximum endpoint number used in the descriptors for this firmware project + +//Device descriptor - if these two definitions are not defined then +// a const USB_DEVICE_DESCRIPTOR variable by the exact name of device_dsc +// must exist. +#define USB_USER_DEVICE_DESCRIPTOR &device_dsc +#define USB_USER_DEVICE_DESCRIPTOR_INCLUDE extern const USB_DEVICE_DESCRIPTOR device_dsc + +//Configuration descriptors - if these two definitions do not exist then +// a const BYTE *const variable named exactly USB_CD_Ptr[] must exist. +#define USB_USER_CONFIG_DESCRIPTOR USB_CD_Ptr +#define USB_USER_CONFIG_DESCRIPTOR_INCLUDE extern const uint8_t *const USB_CD_Ptr[] + + +//------------------------------------------------------------------------------ +//Select an endpoint ping-pong bufferring mode. Some microcontrollers only +//support certain modes. For most applications, it is recommended to use either +//the USB_PING_PONG__FULL_PING_PONG or USB_PING_PONG__EP0_OUT_ONLY options. +//The other settings are supported on some devices, but they are not +//recommended, as they offer inferior control transfer timing performance. +//See inline code comments in usb_device.c for additional details. +//Enabling ping pong bufferring on an endpoint generally increases firmware +//overhead somewhat, but when both buffers are used simultaneously in the +//firmware, can offer better sustained bandwidth, especially for OUT endpoints. +//------------------------------------------------------ +//#define USB_PING_PONG_MODE USB_PING_PONG__NO_PING_PONG //Not recommended +#define USB_PING_PONG_MODE USB_PING_PONG__FULL_PING_PONG //A good all around setting +//#define USB_PING_PONG_MODE USB_PING_PONG__EP0_OUT_ONLY //Another good setting +//#define USB_PING_PONG_MODE USB_PING_PONG__ALL_BUT_EP0 //Not recommended +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +//Select a USB stack operating mode. In the USB_INTERRUPT mode, the USB stack +//main task handler gets called only when necessary as an interrupt handler. +//This can potentially minimize CPU utilization, but adds context saving +//and restoring overhead associated with interrupts, which can potentially +//decrease performance. +//When the USB_POLLING mode is selected, the USB stack main task handler +//(ex: USBDeviceTasks()) must be called periodically by the application firmware +//at a minimum rate as described in the inline code comments in usb_device.c. +//------------------------------------------------------ +#define USB_POLLING +//#define USB_INTERRUPT +//------------------------------------------------------------------------------ + +/* Parameter definitions are defined in usb_device.h */ +#define USB_PULLUP_OPTION USB_PULLUP_ENABLE +//#define USB_PULLUP_OPTION USB_PULLUP_DISABLED + +#define USB_TRANSCEIVER_OPTION USB_INTERNAL_TRANSCEIVER +//External Transceiver support is not available on all product families. Please +// refer to the product family datasheet for more information if this feature +// is available on the target processor. +//#define USB_TRANSCEIVER_OPTION USB_EXTERNAL_TRANSCEIVER + +#define USB_SPEED_OPTION USB_FULL_SPEED +//#define USB_SPEED_OPTION USB_LOW_SPEED //(this mode is only supported on some microcontrollers) + +//------------------------------------------------------------------------------------------------------------------ +//Option to enable auto-arming of the status stage of control transfers, if no +//"progress" has been made for the USB_STATUS_STAGE_TIMEOUT value. +//If progress is made (any successful transactions completing on EP0 IN or OUT) +//the timeout counter gets reset to the USB_STATUS_STAGE_TIMEOUT value. +// +//During normal control transfer processing, the USB stack or the application +//firmware will call USBCtrlEPAllowStatusStage() as soon as the firmware is finished +//processing the control transfer. Therefore, the status stage completes as +//quickly as is physically possible. The USB_ENABLE_STATUS_STAGE_TIMEOUTS +//feature, and the USB_STATUS_STAGE_TIMEOUT value are only relevant, when: +//1. The application uses the USBDeferStatusStage() API function, but never calls +// USBCtrlEPAllowStatusStage(). Or: +//2. The application uses host to device (OUT) control transfers with data stage, +// and some abnormal error occurs, where the host might try to abort the control +// transfer, before it has sent all of the data it claimed it was going to send. +// +//If the application firmware never uses the USBDeferStatusStage() API function, +//and it never uses host to device control transfers with data stage, then +//it is not required to enable the USB_ENABLE_STATUS_STAGE_TIMEOUTS feature. + +#define USB_ENABLE_STATUS_STAGE_TIMEOUTS //Comment this out to disable this feature. + +//Section 9.2.6 of the USB 2.0 specifications indicate that: +//1. Control transfers with no data stage: Status stage must complete within +// 50ms of the start of the control transfer. +//2. Control transfers with (IN) data stage: Status stage must complete within +// 50ms of sending the last IN data packet in fullfilment of the data stage. +//3. Control transfers with (OUT) data stage: No specific status stage timing +// requirement. However, the total time of the entire control transfer (ex: +// including the OUT data stage and IN status stage) must not exceed 5 seconds. +// +//Therefore, if the USB_ENABLE_STATUS_STAGE_TIMEOUTS feature is used, it is suggested +//to set the USB_STATUS_STAGE_TIMEOUT value to timeout in less than 50ms. If the +//USB_ENABLE_STATUS_STAGE_TIMEOUTS feature is not enabled, then the USB_STATUS_STAGE_TIMEOUT +//parameter is not relevant. + +#define USB_STATUS_STAGE_TIMEOUT (uint8_t)45 //Approximate timeout in milliseconds, except when + //USB_POLLING mode is used, and USBDeviceTasks() is called at < 1kHz + //In this special case, the timeout becomes approximately: +//Timeout(in milliseconds) = ((1000 * (USB_STATUS_STAGE_TIMEOUT - 1)) / (USBDeviceTasks() polling frequency in Hz)) +//------------------------------------------------------------------------------------------------------------------ + +#define USB_SUPPORT_DEVICE + +#define USB_NUM_STRING_DESCRIPTORS 3 //Set this number to match the total number of string descriptors that are implemented in the usb_descriptors.c file + +/******************************************************************* + * Event disable options + * Enable a definition to suppress a specific event. By default + * all events are sent. + *******************************************************************/ +//#define USB_DISABLE_SUSPEND_HANDLER +//#define USB_DISABLE_WAKEUP_FROM_SUSPEND_HANDLER +//#define USB_DISABLE_SOF_HANDLER +//#define USB_DISABLE_TRANSFER_TERMINATED_HANDLER +//#define USB_DISABLE_ERROR_HANDLER +//#define USB_DISABLE_NONSTANDARD_EP0_REQUEST_HANDLER +//#define USB_DISABLE_SET_DESCRIPTOR_HANDLER +//#define USB_DISABLE_SET_CONFIGURATION_HANDLER +//#define USB_DISABLE_TRANSFER_COMPLETE_HANDLER + +/** DEVICE CLASS USAGE *********************************************/ +#define USB_USE_HID + +/** ENDPOINTS ALLOCATION *******************************************/ + +/* HID */ +#define HID_INTF_ID 0x00 +#define JOYSTICK_EP 1 +#define HID_INT_OUT_EP_SIZE 64 +#define HID_INT_IN_EP_SIZE 64 +#define HID_NUM_OF_DSC 1 +#define HID_RPT01_SIZE 49 + +/** DEFINITIONS ****************************************************/ + +#endif //USBCFG_H diff --git a/inc/usb/usb_device.h b/inc/usb/usb_device.h new file mode 100644 index 0000000..c8ecc9d --- /dev/null +++ b/inc/usb/usb_device.h @@ -0,0 +1,2054 @@ +// DOM-IGNORE-BEGIN +/******************************************************************************* +Copyright 2015 Microchip Technology Inc. (www.microchip.com) + +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. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ +//DOM-IGNORE-END + +/******************************************************************************* + Module for Microchip USB Library + + Company: + Microchip Technology Inc. + + File Name: + usb_device.h + + Summary: + Defines types and APIs associated with the USB device stack. + + Description: + Defines types and APIs associated with the USB device stack. +*******************************************************************************/ + +#ifndef _USB_DEVICE_H +#define _USB_DEVICE_H + +#include + +#include "usb_common.h" +#include "usb_config.h" + +#if defined(__XC8) + #define __attribute__(a) +#endif + +/** DEFINITIONS ****************************************************/ + +//USB_HANDLE is a pointer to an entry in the BDT. This pointer can be used +// to read the length of the last transfer, the status of the last transfer, +// and various other information. Insure to initialize USB_HANDLE objects +// to NULL so that they are in a known state during their first usage. +#define USB_HANDLE void* + +#define USB_EP0_ROM 0x00 //Data comes from RAM +#define USB_EP0_RAM 0x01 //Data comes from const +#define USB_EP0_BUSY 0x80 //The PIPE is busy +#define USB_EP0_INCLUDE_ZERO 0x40 //include a trailing zero packet +#define USB_EP0_NO_DATA 0x00 //no data to send +#define USB_EP0_NO_OPTIONS 0x00 //no options set + +/******************************************************************** + * Standard Request Codes + * USB 2.0 Spec Ref Table 9-4 + *******************************************************************/ + +/* USB Device States as returned by USBGetDeviceState(). Only the defenitions + for these states should be used. The actual value for each state should + not be relied upon as constant and may change based on the implementation. */ +typedef enum +{ + /* Detached is the state in which the device is not attached to the bus. When + in the detached state a device should not have any pull-ups attached to either + the D+ or D- line. */ + DETACHED_STATE + /*DOM-IGNORE-BEGIN*/ = 0x00 /*DOM-IGNORE-END*/, + /* Attached is the state in which the device is attached ot the bus but the + hub/port that it is attached to is not yet configured. */ + ATTACHED_STATE + /*DOM-IGNORE-BEGIN*/ = 0x01 /*DOM-IGNORE-END*/, + /* Powered is the state in which the device is attached to the bus and the + hub/port that it is attached to is configured. */ + POWERED_STATE + /*DOM-IGNORE-BEGIN*/ = 0x02 /*DOM-IGNORE-END*/, + /* Default state is the state after the device receives a RESET command from + the host. */ + DEFAULT_STATE + /*DOM-IGNORE-BEGIN*/ = 0x04 /*DOM-IGNORE-END*/, + /* Address pending state is not an official state of the USB defined states. + This state is internally used to indicate that the device has received a + SET_ADDRESS command but has not received the STATUS stage of the transfer yet. + The device is should not switch addresses until after the STATUS stage is + complete. */ + ADR_PENDING_STATE + /*DOM-IGNORE-BEGIN*/ = 0x08 /*DOM-IGNORE-END*/, + /* Address is the state in which the device has its own specific address on the + bus. */ + ADDRESS_STATE + /*DOM-IGNORE-BEGIN*/ = 0x10 /*DOM-IGNORE-END*/, + /* Configured is the state where the device has been fully enumerated and is + operating on the bus. The device is now allowed to execute its application + specific tasks. It is also allowed to increase its current consumption to the + value specified in the configuration descriptor of the current configuration. + */ + CONFIGURED_STATE + /*DOM-IGNORE-BEGIN*/ = 0x20 /*DOM-IGNORE-END*/ +} USB_DEVICE_STATE; + + +/* USB device stack events description here - DWF */ +typedef enum +{ + // Notification that a SET_CONFIGURATION() command was received (device) + EVENT_CONFIGURED + /*DOM-IGNORE-BEGIN*/ = EVENT_DEVICE_STACK_BASE /*DOM-IGNORE-END*/, + + // A SET_DESCRIPTOR request was received (device) + EVENT_SET_DESCRIPTOR, + + // An endpoint 0 request was received that the stack did not know how to + // handle. This is most often a request for one of the class drivers. + // Please refer to the class driver documentation for information related + // to what to do if this request is received. (device) + EVENT_EP0_REQUEST, + +// // A USB transfer has completed. The data associated with this event is of +// // the data type HOST_TRANSFER_DATA if the event is generated from the host +// // stack. +// EVENT_TRANSFER, +// +// // A USB Start of Frame token has been received. This event is not +// // used by the Host stack. +// EVENT_SOF, +// +// // Device-mode resume received. This event is not used by the Host stack. +// EVENT_RESUME, +// +// // Device-mode suspend/idle event received. This event is not used by the +// // Host stack. +// EVENT_SUSPEND, +// +// // Device-mode bus reset received. This event is not used by the Host +// // stack. +// EVENT_RESET, + +// // Device Mode: A setup packet received (data: SETUP_PKT). This event is +// // not used by the Host stack. +// EVENT_SETUP, + + // Device-mode USB cable has been attached. This event is not used by the + // Host stack. The client driver may provide an application event when a + // device attaches. + EVENT_ATTACH, + + // A user transfer was terminated by the stack. This event will pass back + // the value of the handle that was terminated. Compare this value against + // the current valid handles to determine which transfer was terminated. + EVENT_TRANSFER_TERMINATED + +} USB_DEVICE_STACK_EVENTS; + +/** Function Prototypes **********************************************/ + + +/******************************************************************************/ +/** External API Functions ****************************************************/ +/******************************************************************************/ + +/************************************************************************** + Function: + void USBDeviceInit(void) + + Description: + This function initializes the device stack it in the default state. The + USB module will be completely reset including all of the internal + variables, registers, and interrupt flags. + + Precondition: + This function must be called before any of the other USB Device + functions can be called, including USBDeviceTasks(). + + Parameters: + None + + Return Values: + None + + Remarks: + None + + **************************************************************************/ +void USBDeviceInit(void); + +/************************************************************************** + Function: + void USBDeviceTasks(void) + + Summary: + This function is the main state machine/transaction handler of the USB + device side stack. When the USB stack is operated in "USB_POLLING" mode + (usb_config.h user option) the USBDeviceTasks() function should be called + periodically to receive and transmit packets through the stack. This + function also takes care of control transfers associated with the USB + enumeration process, and detecting various USB events (such as suspend). + This function should be called at least once every 1.8ms during the USB + enumeration process. After the enumeration process is complete (which can + be determined when USBGetDeviceState() returns CONFIGURED_STATE), the + USBDeviceTasks() handler may be called the faster of: either once + every 9.8ms, or as often as needed to make sure that the hardware USTAT + FIFO never gets full. A good rule of thumb is to call USBDeviceTasks() at + a minimum rate of either the frequency that USBTransferOnePacket() gets + called, or, once/1.8ms, whichever is faster. See the inline code comments + near the top of usb_device.c for more details about minimum timing + requirements when calling USBDeviceTasks(). + + When the USB stack is operated in "USB_INTERRUPT" mode, it is not necessary + to call USBDeviceTasks() from the main loop context. In the USB_INTERRUPT + mode, the USBDeviceTasks() handler only needs to execute when a USB + interrupt occurs, and therefore only needs to be called from the interrupt + context. + + Description: + This function is the main state machine/transaction handler of the USB + device side stack. When the USB stack is operated in "USB_POLLING" mode + (usb_config.h user option) the USBDeviceTasks() function should be called + periodically to receive and transmit packets through the stack. This + function also takes care of control transfers associated with the USB + enumeration process, and detecting various USB events (such as suspend). + This function should be called at least once every 1.8ms during the USB + enumeration process. After the enumeration process is complete (which can + be determined when USBGetDeviceState() returns CONFIGURED_STATE), the + USBDeviceTasks() handler may be called the faster of: either once + every 9.8ms, or as often as needed to make sure that the hardware USTAT + FIFO never gets full. A good rule of thumb is to call USBDeviceTasks() at + a minimum rate of either the frequency that USBTransferOnePacket() gets + called, or, once/1.8ms, whichever is faster. See the inline code comments + near the top of usb_device.c for more details about minimum timing + requirements when calling USBDeviceTasks(). + + When the USB stack is operated in "USB_INTERRUPT" mode, it is not necessary + to call USBDeviceTasks() from the main loop context. In the USB_INTERRUPT + mode, the USBDeviceTasks() handler only needs to execute when a USB + interrupt occurs, and therefore only needs to be called from the interrupt + context. + + Typical usage: + + void main(void) + { + USBDeviceInit(); + while(1) + { + USBDeviceTasks(); //Takes care of enumeration and other USB events + if((USBGetDeviceState() \< CONFIGURED_STATE) || + (USBIsDeviceSuspended() == true)) + { + //Either the device is not configured or we are suspended, + // so we don't want to execute any USB related application code + continue; //go back to the top of the while loop + } + else + { + //Otherwise we are free to run USB and non-USB related user + //application code. + UserApplication(); + } + } + } + + + Precondition: + Make sure the USBDeviceInit() function has been called prior to calling + USBDeviceTasks() for the first time. + Remarks: + USBDeviceTasks() does not need to be called while in the USB suspend mode, + if the user application firmware in the USBCBSuspend() callback function + enables the ACTVIF USB interrupt source and put the microcontroller into + sleep mode. If the application firmware decides not to sleep the + microcontroller core during USB suspend (ex: continues running at full + frequency, or clock switches to a lower frequency), then the USBDeviceTasks() + function must still be called periodically, at a rate frequent enough to + ensure the 10ms resume recovery interval USB specification is met. Assuming + a worst case primary oscillator and PLL start up time of <5ms, then + USBDeviceTasks() should be called once every 5ms in this scenario. + + When the USB cable is detached, or the USB host is not actively powering + the VBUS line to +5V nominal, the application firmware does not always have + to call USBDeviceTasks() frequently, as no USB activity will be taking + place. However, if USBDeviceTasks() is not called regularly, some + alternative means of promptly detecting when VBUS is powered (indicating + host attachment), or not powered (host powered down or USB cable unplugged) + is still needed. For self or dual self/bus powered USB applications, see + the USBDeviceAttach() and USBDeviceDetach() API documentation for additional + considerations. + */ +void USBDeviceTasks(void); + + +/******************************************************************************* + Function: + void USBEnableEndpoint(uint8_t ep, uint8_t options) + + Summary: + This function will enable the specified endpoint with the specified + options + Description: + This function will enable the specified endpoint with the specified + options. + + Typical Usage: + + void USBCBInitEP(void) + { + USBEnableEndpoint(MSD_DATA_IN_EP,USB_IN_ENABLED|USB_OUT_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP); + USBMSDInit(); + } + + + In the above example endpoint number MSD_DATA_IN_EP is being configured + for both IN and OUT traffic with handshaking enabled. Also since + MSD_DATA_IN_EP is not endpoint 0 (MSD does not allow this), then we can + explicitly disable SETUP packets on this endpoint. + Conditions: + None + Input: + uint8_t ep - the endpoint to be configured + uint8_t options - optional settings for the endpoint. The options should + be ORed together to form a single options string. The + available optional settings for the endpoint. The + options should be ORed together to form a single options + string. The available options are the following\: + * USB_HANDSHAKE_ENABLED enables USB handshaking (ACK, + NAK) + * USB_HANDSHAKE_DISABLED disables USB handshaking (ACK, + NAK) + * USB_OUT_ENABLED enables the out direction + * USB_OUT_DISABLED disables the out direction + * USB_IN_ENABLED enables the in direction + * USB_IN_DISABLED disables the in direction + * USB_ALLOW_SETUP enables control transfers + * USB_DISALLOW_SETUP disables control transfers + * USB_STALL_ENDPOINT STALLs this endpoint + Return: + None + Remarks: + None + *****************************************************************************/ +void USBEnableEndpoint(uint8_t ep, uint8_t options); + + +/************************************************************************* + Function: + USB_HANDLE USBTransferOnePacket(uint8_t ep, uint8_t dir, uint8_t* data, uint8_t len) + + Summary: + Transfers a single packet (one transaction) of data on the USB bus. + + Description: + The USBTransferOnePacket() function prepares a USB endpoint + so that it may send data to the host (an IN transaction), or + receive data from the host (an OUT transaction). The + USBTransferOnePacket() function can be used both to receive and + send data to the host. This function is the primary API function + provided by the USB stack firmware for sending or receiving application + data over the USB port. + + The USBTransferOnePacket() is intended for use with all application + endpoints. It is not used for sending or receiving application data + through endpoint 0 by using control transfers. Separate API + functions, such as USBEP0Receive(), USBEP0SendRAMPtr(), and + USBEP0SendROMPtr() are provided for this purpose. + + The USBTransferOnePacket() writes to the Buffer Descriptor Table (BDT) + entry associated with an endpoint buffer, and sets the UOWN bit, which + prepares the USB hardware to allow the transaction to complete. The + application firmware can use the USBHandleBusy() macro to check the + status of the transaction, to see if the data has been successfully + transmitted yet. + + + Typical Usage + + //make sure that the we are in the configured state + if(USBGetDeviceState() == CONFIGURED_STATE) + { + //make sure that the last transaction isn't busy by checking the handle + if(!USBHandleBusy(USBInHandle)) + { + //Write the new data that we wish to send to the host to the INPacket[] array + INPacket[0] = USEFUL_APPLICATION_VALUE1; + INPacket[1] = USEFUL_APPLICATION_VALUE2; + //INPacket[2] = ... (fill in the rest of the packet data) + + //Send the data contained in the INPacket[] array through endpoint "EP_NUM" + USBInHandle = USBTransferOnePacket(EP_NUM,IN_TO_HOST,(uint8_t*)&INPacket[0],sizeof(INPacket)); + } + } + + + Conditions: + Before calling USBTransferOnePacket(), the following should be true. + 1. The USB stack has already been initialized (USBDeviceInit() was called). + 2. A transaction is not already pending on the specified endpoint. This + is done by checking the previous request using the USBHandleBusy() + macro (see the typical usage example). + 3. The host has already sent a set configuration request and the + enumeration process is complete. + This can be checked by verifying that the USBGetDeviceState() + macro returns "CONFIGURED_STATE", prior to calling + USBTransferOnePacket(). + + Input: + uint8_t ep - The endpoint number that the data will be transmitted or + received on + uint8_t dir - The direction of the transfer + This value is either OUT_FROM_HOST or IN_TO_HOST + uint8_t* data - For IN transactions: pointer to the RAM buffer containing + the data to be sent to the host. For OUT transactions: pointer + to the RAM buffer that the received data should get written to. + uint8_t len - Length of the data needing to be sent (for IN transactions). + For OUT transactions, the len parameter should normally be set + to the endpoint size specified in the endpoint descriptor. + + Return Values: + USB_HANDLE - handle to the transfer. The handle is a pointer to + the BDT entry associated with this transaction. The + status of the transaction (ex: if it is complete or still + pending) can be checked using the USBHandleBusy() macro + and supplying the USB_HANDLE provided by + USBTransferOnePacket(). + + Remarks: + If calling the USBTransferOnePacket() function from within the USBCBInitEP() + callback function, the set configuration is still being processed and the + USBDeviceState may not be == CONFIGURED_STATE yet. In this special case, + the USBTransferOnePacket() may still be called, but make sure that the + endpoint has been enabled and initialized by the USBEnableEndpoint() + function first. + + *************************************************************************/ +USB_HANDLE USBTransferOnePacket(uint8_t ep,uint8_t dir,uint8_t* data,uint8_t len); + +/******************************************************************** + Function: + void USBStallEndpoint(uint8_t ep, uint8_t dir) + + Summary: + Configures the specified endpoint to send STALL to the host, the next + time the host tries to access the endpoint. + + PreCondition: + None + + Parameters: + uint8_t ep - The endpoint number that should be configured to send STALL. + uint8_t dir - The direction of the endpoint to STALL, either + IN_TO_HOST or OUT_FROM_HOST. + + Return Values: + None + + Remarks: + None + + *******************************************************************/ +void USBStallEndpoint(uint8_t ep, uint8_t dir); +/************************************************************************** + Function: + void USBCancelIO(uint8_t endpoint) + + Description: + This function cancels the transfers pending on the specified endpoint. + This function can only be used after a SETUP packet is received and + before that setup packet is handled. This is the time period in which + the EVENT_EP0_REQUEST is thrown, before the event handler function + returns to the stack. + + Precondition: + + Parameters: + uint8_t endpoint - the endpoint number you wish to cancel the transfers for + + Return Values: + None + + Remarks: + None + + **************************************************************************/ +void USBCancelIO(uint8_t endpoint); + +/************************************************************************** + Function: + void USBDeviceDetach(void) + + Summary: + This function configures the USB module to "soft detach" itself from + the USB host. + + Description: + This function configures the USB module to perform a "soft detach" + operation, by disabling the D+ (or D-) ~1.5k pull up resistor, which + lets the host know the device is present and attached. This will make + the host think that the device has been unplugged. This is potentially + useful, as it allows the USB device to force the host to re-enumerate + the device (on the firmware has re-enabled the USB module/pull up, by + calling USBDeviceAttach(), to "soft re-attach" to the host). + + Precondition: + Should only be called when USB_INTERRUPT is defined. See remarks + section if USB_POLLING mode option is being used (usb_config.h option). + + Additionally, this function should only be called from the main() loop + context. Do not call this function from within an interrupt handler, as + this function may modify global interrupt enable bits and settings. + + Parameters: + None + + Return Values: + None + + Remarks: + If the application firmware calls USBDeviceDetach(), it is strongly + recommended that the firmware wait at least >= 80ms before calling + USBDeviceAttach(). If the firmware performs a soft detach, and then + re-attaches too soon (ex: after a few micro seconds for instance), some + hosts may interpret this as an unexpected "glitch" rather than as a + physical removal/re-attachment of the USB device. In this case the host + may simply ignore the event without re-enumerating the device. To + ensure that the host properly detects and processes the device soft + detach/re-attach, it is recommended to make sure the device remains + detached long enough to mimic a real human controlled USB + unplug/re-attach event (ex: after calling USBDeviceDetach(), do not + call USBDeviceAttach() for at least 80+ms, preferably longer. + + Neither the USBDeviceDetach() or USBDeviceAttach() functions are blocking + or take long to execute. It is the application firmwares + responsibility for adding the 80+ms delay, when using these API + functions. + + Note: The Windows plug and play event handler processing is fairly + slow, especially in certain versions of Windows, and for certain USB + device classes. It has been observed that some device classes need to + provide even more USB detach dwell interval (before calling + USBDeviceAttach()), in order to work correctly after re-enumeration. + If the USB device is a CDC class device, it is recommended to wait + at least 1.5 seconds or longer, before soft re-attaching to the host, + to provide the plug and play event handler enough time to finish + processing the removal event, before the re-attach occurs. + + If the application is using the USB_POLLING mode option, then the + USBDeviceDetach() and USBDeviceAttach() functions are not available. + In this mode, the USB stack relies on the "#define USE_USB_BUS_SENSE_IO" + and "#define USB_BUS_SENSE" options in the + HardwareProfile � [platform name].h file. + + When using the USB_POLLING mode option, and the + "#define USE_USB_BUS_SENSE_IO" definition has been commented out, then + the USB stack assumes that it should always enable the USB module at + pretty much all times. Basically, anytime the application firmware + calls USBDeviceTasks(), the firmware will automatically enable the USB + module. This mode would typically be selected if the application was + designed to be a purely bus powered device. In this case, the + application is powered from the +5V VBUS supply from the USB port, so + it is correct and sensible in this type of application to power up and + turn on the USB module, at anytime that the microcontroller is + powered (which implies the USB cable is attached and the host is also + powered). + + In a self powered application, the USB stack is designed with the + intention that the user will enable the "#define USE_USB_BUS_SENSE_IO" + option in the HardwareProfile � [platform name].h file. When this + option is defined, then the USBDeviceTasks() function will automatically + check the I/O pin port value of the designated pin (based on the + #define USB_BUS_SENSE option in the HardwareProfile � [platform name].h + file), every time the application calls USBDeviceTasks(). If the + USBDeviceTasks() function is executed and finds that the pin defined by + the #define USB_BUS_SENSE is in a logic low state, then it will + automatically disable the USB module and tri-state the D+ and D- pins. + If however the USBDeviceTasks() function is executed and finds the pin + defined by the #define USB_BUS_SENSE is in a logic high state, then it + will automatically enable the USB module, if it has not already been + enabled. + + **************************************************************************/ +void USBDeviceDetach(void); + +/*DOM-IGNORE-BEGIN*/ +#if !defined(USB_INTERRUPT) + #define USBDeviceDetach() +#endif +/*DOM-IGNORE-END*/ + +/************************************************************************** + Function: + void USBDeviceAttach(void) + + Summary: + Checks if VBUS is present, and that the USB module is not already + initalized, and if so, enables the USB module so as to signal device + attachment to the USB host. + + Description: + This function indicates to the USB host that the USB device has been + attached to the bus. This function needs to be called in order for the + device to start to enumerate on the bus. + + Precondition: + Should only be called when USB_INTERRUPT is defined. Also, should only + be called from the main() loop context. Do not call USBDeviceAttach() + from within an interrupt handler, as the USBDeviceAttach() function + may modify global interrupt enable bits and settings. + + For normal USB devices: + Make sure that if the module was previously on, that it has been turned off + for a long time (ex: 100ms+) before calling this function to re-enable the module. + If the device turns off the D+ (for full speed) or D- (for low speed) ~1.5k ohm + pull up resistor, and then turns it back on very quickly, common hosts will sometimes + reject this event, since no human could ever unplug and re-attach a USB device in a + microseconds (or nanoseconds) timescale. The host could simply treat this as some kind + of glitch and ignore the event altogether. + Parameters: + None + + Return Values: + None + + Remarks: + See also the USBDeviceDetach() API function documentation. +****************************************************************************/ +void USBDeviceAttach(void); + +/*DOM-IGNORE-BEGIN*/ +#if !defined(USB_INTERRUPT) + #define USBDeviceAttach() +#endif +/*DOM-IGNORE-END*/ + + +/******************************************************************************* + Function: void USBCtrlEPAllowStatusStage(void); + + Summary: This function prepares the proper endpoint 0 IN or endpoint 0 OUT + (based on the controlTransferState) to allow the status stage packet + of a control transfer to complete. This function gets used + internally by the USB stack itself, but it may also be called from + the application firmware, IF the application firmware called + the USBDeferStatusStage() function during the initial processing + of the control transfer request. In this case, the application + must call the USBCtrlEPAllowStatusStage() once, after it has fully + completed processing and handling the data stage portion of the + request. + + If the application firmware has no need for delaying control + transfers, and therefore never calls USBDeferStatusStage(), then the + application firmware should not call USBCtrlEPAllowStatusStage(). + + Description: + + Conditions: + None + + Input: + + Return: + + Remarks: + None + *****************************************************************************/ +void USBCtrlEPAllowStatusStage(void); + + + +/******************************************************************************* + Function: void USBCtrlEPAllowDataStage(void); + + Summary: This function allows the data stage of either a host-to-device or + device-to-host control transfer (with data stage) to complete. + This function is meant to be used in conjunction with either the + USBDeferOUTDataStage() or USBDeferINDataStage(). If the firmware + does not call either USBDeferOUTDataStage() or USBDeferINDataStage(), + then the firmware does not need to manually call + USBCtrlEPAllowDataStage(), as the USB stack will call this function + instead. + + Description: + + Conditions: A control transfer (with data stage) should already be pending, + if the firmware calls this function. Additionally, the firmware + should have called either USBDeferOUTDataStage() or + USBDeferINDataStage() at the start of the control transfer, if + the firmware will be calling this function manually. + + Input: + + Return: + + Remarks: + *****************************************************************************/ +void USBCtrlEPAllowDataStage(void); + + +/******************************************************************************* + Function: void USBDeferOUTDataStage(void); + + Summary: This function will cause the USB hardware to continuously NAK the + OUT data packets sent from the host, during the data stage of a + device to host control transfer. This allows the firmware more time + to prepare the RAM buffer that will eventually be used to receive the + data from the host. This is also useful, if the firmware wishes to + receive the OUT data in a different context than what the + USBDeviceTasks() function executes at. + + Calling this function (macro) will assert ownership of the currently + pending control transfer. Therefore, the USB stack will not STALL + when it reaches the data stage of the control transfer, even if the + firmware has not (yet) called the USBEP0Receive() API function. + However, the application firmware must still (eventually, once it is + ready) call one of the aforementioned API function. + + Example Usage: + + 1. Host sends a SETUP packet to the device, requesting a host to + device control transfer, with data stage (OUT data packets). + 2. USBDeviceTasks() executes, and then calls the USBCBCheckOtherReq() + callback event handler. The USBCBCheckOtherReq() calls the + application specific/device class specific handler that detects + the type of control transfer. + 3. If the firmware needs more time before it wishes to receive the + first OUT data packet, or, if the firmware wishes to process the + command in a different context, then it may call + USBDeferOUTDataStage(), in the context of the + USBCBCheckOtherReq() handler function. + 4. If the firmware called USBDeferOUTDataStage() in step #3 above, + then the hardware will NAK the OUT data packets sent by the + host, for the OUT data stage. + 5. Once the firmware is ready, it should then call USBEP0Receive(), + to prepare the USB stack to receive the OUT data from the host, + and to write it to the user specified buffer. + 6. The firmware should now call USBCtrlEPAllowDataStage(). This + will allow the data stage to complete. Once all OUT data has + been received, the user callback function (provided by the + function pointer provided when calling USBEP0Receive()) will + get called. + 7. Once all data has been received from the host, the status stage + (a 0-byte IN packet) will complete automatically (assuming the + firmware did not call USBDeferStatusStage() during step #3). + + + Description: + + Conditions: Before calling USBDeferOUTDataStage(), the firmware should first + verify that the control transfer has a data stage, and that + it is of type host-to-device (OUT). + + Input: + + Return: + + Remarks: Section 9.2.6 of the official USB 2.0 specifications indicates that + the USB device must be able to receive all bytes and complete the + control transfer within a maximum of 5 seconds. + + If the firmware calls USBDeferOUTDataStage(), it must eventually call + USBEP0Receive(), and then call USBCtrlEPAllowDataStage(). If it does + not do this, the control transfer will never be able to complete. + This will break the USB connection, as the host needs to be able to + communicate over EP0, in order to perform basic tasks including + enumeration. + + The firmware should never call both USBDeferINDataStage() and + USBDeferOUTDataStage() during the same control transfer. These + functions are mutually exclusive (a control transfer with data stage + can never contain both IN and OUT data packets during the data stage). + *****************************************************************************/ +void USBDeferOUTDataStage(void); +extern volatile bool USBDeferOUTDataStagePackets; +/*DOM-IGNORE-BEGIN*/ +#define USBDeferOUTDataStage() {USBDeferOUTDataStagePackets = true; outPipes[0].info.bits.busy = 1;} +/*DOM-IGNORE-END*/ + +/******************************************************************************* + Function: void USBDeferStatusStage(void); + + Summary: Calling this function will prevent the USB stack from automatically + enabling the status stage for the currently pending control transfer + from completing immediately after all data bytes have been sent or + received. This is useful if a class handler or USB application + firmware project uses control transfers for sending/receiving data + over EP0, but requires time in order to finish processing and/or to + consume the data. + + For example: Consider an application which receives OUT data from the + USB host, through EP0 using control transfers. Now assume that this + application wishes to do something time consuming with this data (ex: + transmit it to and save it to an external EEPconst device, connected + via SPI/I2C/etc.). In this case, it would typically be desirable to + defer allowing the USB status stage of the control transfer to complete, + until after the data has been fully sent to the EEPconst device and saved. + + If the USB class handler firmware that processes the control transfer + SETUP packet determines that it will need extra time to complete the + control transfer, it may optionally call USBDeferStatusStage(). If it + does so, it is then the responsibility of the application firmware to + eventually call USBCtrlEPAllowStatusStage(), once the firmware has + finished processing the data associated with the control transfer. + + If the firmware call USBDeferStatusStage(), but never calls + USBCtrlEPAllowStatusStage(), then one of two possibilities will occur. + + 1. If the "USB_ENABLE_STATUS_STAGE_TIMEOUTS" option is commented in + usb_config.h, then the status stage of the control transfer will + never be able to complete. This is an error case and should be + avoided. + 2. If the "USB_ENABLE_STATUS_STAGE_TIMEOUTS" option is enabled in + usb_config.h, then the USBDeviceTasks() function will + automatically call USBCtrlEPAllowStatusStage(), after the + "USB_STATUS_STAGE_TIMEOUT" has elapsed, since the last quanta of + "progress" has occurred in the control transfer. Progress is + defined as the last successful transaction completing on EP0 IN or + EP0 OUT. + Although the timeouts feature allows the status stage to + [eventually] complete, it is still preferable to manually call + USBCtrlEPAllowStatusStage() after the application firmware has + finished processing/consuming the control transfer data, as this + will allow for much faster processing of control transfers, and + therefore much higher data rates and better user responsiveness. + Description: + + Conditions: + None + + Input: + + Return: + + Remarks: If this function is called, is should get called after the SETUP + packet has arrived (the control transfer has started), but before + the USBCtrlEPServiceComplete() function has been called by the USB + stack. Therefore, the normal place to call USBDeferStatusStage() + would be from within the USBCBCheckOtherReq() handler context. For + example, in a HID application using control transfers, the + USBDeferStatusStage() function would be called from within the + USER_GET_REPORT_HANDLER or USER_SET_REPORT_HANDLER functions. + *****************************************************************************/ +void USBDeferStatusStage(void); +extern volatile bool USBDeferStatusStagePacket; +/*DOM-IGNORE-BEGIN*/ +#define USBDeferStatusStage() {USBDeferStatusStagePacket = true;} +/*DOM-IGNORE-END*/ + + +/******************************************************************************* + Function: bool USBOUTDataStageDeferred(void); + + Summary: Returns true if a control transfer with OUT data stage is pending, + and the firmware has called USBDeferOUTDataStage(), but has not + yet called USBCtrlEPAllowDataStage(). + Returns false if a control transfer with OUT data stage is either + not pending, or the firmware did not call USBDeferOUTDataStage() + at the start of the control transfer. + + This function (macro) would typically be used in the case where the + USBDeviceTasks() function executes in the interrupt context (ex: + USB_INTERRUPT option selected in usb_config.h), but the firmware + wishes to take care of handling the data stage of the control transfer + in the main loop context. + + In this scenario, typical usage would be: + 1. Host starts a control transfer with OUT data stage. + 2. USBDeviceTasks() (in this scenario, interrupt context) executes. + 3. USBDeviceTasks() calls USBCBCheckOtherReq(), which in turn + determines that the control transfer is class specific, with + OUT data stage. + 4. The user code in USBCBCheckOtherReq() (also in interrupt context, + since it is called from USBDeviceTasks(), and therefore executes + at the same priority/context) calls USBDeferOUTDataStage(). + + 5. Meanwhile, in the main loop context, a polling handler may be + periodically checking if(USBOUTDataStageDeferred() == true). + Ordinarily, it would evaluate false, but when a control transfer + becomes pending, and after the USBDeferOUTDataStage() macro has + been called (ex: in the interrupt context), the if() statement + will evaluate true. In this case, the main loop context can then + take care of receiving the data, by calling USBEP0Receive() and + USBCtrlEPAllowDataStage(). + + Description: + + Conditions: + + Input: + + Return: + + Remarks: + *****************************************************************************/ +bool USBOUTDataStageDeferred(void); +/*DOM-IGNORE-BEGIN*/ +#define USBOUTDataStageDeferred() USBDeferOUTDataStagePackets +/*DOM-IGNORE-END*/ + +/******************************************************************************* + Function: void USBDeferINDataStage(void); + + Summary: This function will cause the USB hardware to continuously NAK the + IN token packets sent from the host, during the data stage of a + device to host control transfer. This allows the firmware more time + to process and prepare the IN data packets that will eventually be + sent to the host. This is also useful, if the firmware needs to + process/prepare the IN data in a different context than what the + USBDeviceTasks() function executes at. + + Calling this function (macro) will assert ownership of the currently + pending control transfer. Therefore, the USB stack will not STALL + when it reaches the data stage of the control transfer, even if the + firmware has not (yet) called the USBEP0SendRAMPtr() or + USBEP0SendROMPtr() API function. However, the application firmware + must still (eventually, once it is ready) call one of the + aforementioned API functions. + + Example Usage: + + 1. Host sends a SETUP packet to the device, requesting a device to + host control transfer, with data stage. + 2. USBDeviceTasks() executes, and then calls the USBCBCheckOtherReq() + callback event handler. The USBCBCheckOtherReq() calls the + application specific/device class specific handler that detects + the type of control transfer. + 3. If the firmware needs more time to prepare the first IN data packet, + or, if the firmware wishes to process the command in a different + context (ex: if USBDeviceTasks() executes as an interrupt handler, + but the IN data stage data needs to be prepared in the main loop + context), then it may call USBDeferINDataStage(), in the context + of the USBCBCheckOtherReq() handler function. + 4. If the firmware called USBDeferINDataStage() in step #3 above, + then the hardware will NAK the IN token packets sent by the + host, for the IN data stage. + 5. Once the firmware is ready, and has successfully prepared the + data to be sent to the host in fulfillment of the control + transfer, it should then call USBEP0SendRAMPtr() or + USBEP0SendROMPtr(), to prepare the USB stack to know how many + bytes to send to the host, and from what source location. + 6. The firmware should now call USBCtrlEPAllowDataStage(). This + will allow the data stage to complete. The USB stack will send + the data buffer specified by the USBEP0SendRAMPtr() or + USBEP0SendROMPtr() function, when it was called. + 7. Once all data has been sent to the host, or if the host performs + early termination, the status stage (a 0-byte OUT packet) will + complete automatically (assuming the firmware did not call + USBDeferStatusStage() during step #3). + + + Description: + + Conditions: Before calling USBDeferINDataStage(), the firmware should first + verify that the control transfer has a data stage, and that + it is of type device-to-host (IN). + + Input: + + Return: + + Remarks: Section 9.2.6 of the official USB 2.0 specifications indicates that + the USB device must return the first IN data packet within 500ms + of the start of the control transfer. In order to meet this + specification, the firmware must call USBEP0SendRAMPtr() or + USBEP0SendROMPtr(), and then call USBCtrlEPAllowDataStage(), in + less than 500ms from the start of the control transfer. + + If the firmware calls USBDeferINDataStage(), it must eventually call + USBEP0SendRAMPtr() or USBEP0SendROMPtr(), and then call + USBCtrlEPAllowDataStage(). If it does not do this, the control + transfer will never be able to complete. + + The firmware should never call both USBDeferINDataStage() and + USBDeferOUTDataStage() during the same control transfer. These + functions are mutually exclusive (a control transfer with data stage + can never contain both IN and OUT data packets during the data stage). + *****************************************************************************/ +void USBDeferINDataStage(void); +extern volatile bool USBDeferINDataStagePackets; +/*DOM-IGNORE-BEGIN*/ +#define USBDeferINDataStage() {USBDeferINDataStagePackets = true; inPipes[0].info.bits.busy = 1;} +/*DOM-IGNORE-END*/ + + + +/******************************************************************************* + Function: bool USBINDataStageDeferred(void); + + Summary: Returns true if a control transfer with IN data stage is pending, + and the firmware has called USBDeferINDataStage(), but has not + yet called USBCtrlEPAllowDataStage(). + Returns false if a control transfer with IN data stage is either + not pending, or the firmware did not call USBDeferINDataStage() + at the start of the control transfer. + + This function (macro) would typically be used in the case where the + USBDeviceTasks() function executes in the interrupt context (ex: + USB_INTERRUPT option selected in usb_config.h), but the firmware + wishes to take care of handling the data stage of the control transfer + in the main loop context. + + In this scenario, typical usage would be: + 1. Host starts a control transfer with IN data stage. + 2. USBDeviceTasks() (in this scenario, interrupt context) executes. + 3. USBDeviceTasks() calls USBCBCheckOtherReq(), which in turn + determines that the control transfer is class specific, with + IN data stage. + 4. The user code in USBCBCheckOtherReq() (also in interrupt context, + since it is called from USBDeviceTasks(), and therefore executes + at the same priority/context) calls USBDeferINDataStage(). + + 5. Meanwhile, in the main loop context, a polling handler may be + periodically checking if(USBINDataStageDeferred() == true). + Ordinarily, it would evaluate false, but when a control transfer + becomes pending, and after the USBDeferINDataStage() macro has + been called (ex: in the interrupt context), the if() statement + will evaluate true. In this case, the main loop context can then + take care of sending the data (when ready), by calling + USBEP0SendRAMPtr() or USBEP0SendROMPtr() and + USBCtrlEPAllowDataStage(). + + Description: + + Conditions: + + Input: + + Return: + + Remarks: + *****************************************************************************/ +bool USBINDataStageDeferred(void); +/*DOM-IGNORE-BEGIN*/ +#define USBINDataStageDeferred() USBDeferINDataStagePackets +/*DOM-IGNORE-END*/ + + + +/******************************************************************** + Function: + bool USBGetRemoteWakeupStatus(void) + + Summary: + This function indicates if remote wakeup has been enabled by the host. + Devices that support remote wakeup should use this function to + determine if it should send a remote wakeup. + + Description: + This function indicates if remote wakeup has been enabled by the host. + Devices that support remote wakeup should use this function to + determine if it should send a remote wakeup. + + If a device does not support remote wakeup (the Remote wakeup bit, bit + 5, of the bmAttributes field of the Configuration descriptor is set to + 1), then it should not send a remote wakeup command to the PC and this + function is not of any use to the device. If a device does support + remote wakeup then it should use this function as described below. + + If this function returns false and the device is suspended, it should + not issue a remote wakeup (resume). + + If this function returns true and the device is suspended, it should + issue a remote wakeup (resume). + + A device can add remote wakeup support by having the _RWU symbol added + in the configuration descriptor (located in the usb_descriptors.c file + in the project). This done in the 8th byte of the configuration + descriptor. For example: + + + const uint8_t configDescriptor1[]={ + 0x09, // Size + USB_DESCRIPTOR_CONFIGURATION, // descriptor type + DESC_CONFIG_WORD(0x0022), // Total length + 1, // Number of interfaces + 1, // Index value of this cfg + 0, // Configuration string index + _DEFAULT | _SELF | _RWU, // Attributes, see usb_device.h + 50, // Max power consumption in 2X mA(100mA) + + //The rest of the configuration descriptor should follow + + + For more information about remote wakeup, see the following section of + the USB v2.0 specification available at www.usb.org: + * Section 9.2.5.2 + * Table 9-10 + * Section 7.1.7.7 + * Section 9.4.5 + + Conditions: + None + + Return Values: + true - Remote Wakeup has been enabled by the host + false - Remote Wakeup is not currently enabled + + Remarks: + None + + *******************************************************************/ +bool USBGetRemoteWakeupStatus(void); +/*DOM-IGNORE-BEGIN*/ +#define USBGetRemoteWakeupStatus() RemoteWakeup +/*DOM-IGNORE-END*/ + +/*************************************************************************** + Function: + USB_DEVICE_STATE USBGetDeviceState(void) + + Summary: + This function will return the current state of the device on the USB. + This function should return CONFIGURED_STATE before an application + tries to send information on the bus. + Description: + This function returns the current state of the device on the USB. This + \function is used to determine when the device is ready to communicate + on the bus. Applications should not try to send or receive data until + this function returns CONFIGURED_STATE. + + It is also important that applications yield as much time as possible + to the USBDeviceTasks() function as possible while the this function + \returns any value between ATTACHED_STATE through CONFIGURED_STATE. + + For more information about the various device states, please refer to + the USB specification section 9.1 available from www.usb.org. + + Typical usage: + + void main(void) + { + USBDeviceInit() + while(1) + { + USBDeviceTasks(); + if((USBGetDeviceState() \< CONFIGURED_STATE) || + (USBIsDeviceSuspended() == true)) + { + //Either the device is not configured or we are suspended + // so we don't want to do execute any application code + continue; //go back to the top of the while loop + } + else + { + //Otherwise we are free to run user application code. + UserApplication(); + } + } + } + + Conditions: + None + Return Values: + USB_DEVICE_STATE - the current state of the device on the bus + + Remarks: + None + ***************************************************************************/ +USB_DEVICE_STATE USBGetDeviceState(void); +/*DOM-IGNORE-BEGIN*/ +#define USBGetDeviceState() USBDeviceState +/*DOM-IGNORE-END*/ + + + +/*************************************************************************** + Function: + bool USBGetSuspendState(void) + + Summary: + This function indicates if the USB port that this device is attached to is + currently suspended. When suspended, it will not be able to transfer data + over the bus. + Description: + This function indicates if the USB port that this device is attached to is + currently suspended. When suspended, it will not be able to transfer data + over the bus. + This function can be used by the application to skip over section of + code that do not need to execute if the device is unable to send data + over the bus. This function can also be used to help determine when it is + legal to perform USB remote wakeup signaling, for devices supporting this + feature. + + Typical usage: + + void main(void) + { + USBDeviceInit() + while(1) + { + USBDeviceTasks(); + if((USBGetDeviceState() \< CONFIGURED_STATE) || + (USBGetSuspendState() == true)) + { + //Either the device is not configured or we are suspended + // so we don't want to do execute any application code + continue; //go back to the top of the while loop + } + else + { + //Otherwise we are free to run user application code. + UserApplication(); + } + } + } + + Conditions: + None + Return Values: + true - the USB port this device is attached to is suspended. + false - the USB port this device is attached to is not suspended. + Remarks: + This function is the same as USBIsBusSuspended(). + ***************************************************************************/ +bool USBGetSuspendState(void); +/*DOM-IGNORE-BEGIN*/ +#define USBGetSuspendState() USBBusIsSuspended +/*DOM-IGNORE-END*/ + +/******************************************************************************* + Function: + bool USBIsDeviceSuspended(void) + + Summary: + This function indicates if the USB module is in suspend mode. + + Description: + This function indicates if the USB module is in suspend mode. This function + does NOT indicate that a suspend request has been received. It only + reflects the state of the USB module. + + Typical Usage: + + if(USBIsDeviceSuspended() == true) + { + return; + } + // otherwise do some application specific tasks + + + Conditions: + None + Input: + None + Return: + None + Remarks: + None + *****************************************************************************/ +bool USBIsDeviceSuspended(void); +/*DOM-IGNORE-BEGIN*/ +#define USBIsDeviceSuspended() USBSuspendControl +/*DOM-IGNORE-END*/ + + +/******************************************************************************* + Function: + bool USBIsBusSuspended(void); + + Summary: + This function indicates if the USB bus is in suspend mode. + + Description: + This function indicates if the USB bus is in suspend mode. This function + is typically used for checking if the conditions are consistent with + performing a USB remote wakeup sequence. + + Typical Usage: + + if((USBIsBusSuspended() == true) && (USBGetRemoteWakeupStatus() == true)) + { + //Check if some stimulus occured, which will be used as the wakeup source + if(sw3 == 0) + { + USBCBSendResume(); //Send the remote wakeup signalling to the host + } + } + // otherwise do some other application specific tasks + + + Conditions: + None + Input: + None + Return: + None + Remarks: + The USBIsBusSuspended() function relies on the USBBusIsSuspended boolean + variable, which gets updated by the USBDeviceTasks() function. Therefore, + in order to be sure the return value is not "stale", it is suggested to make + sure USBDeviceTasks() has executed recently (if using USB polling mode). + *****************************************************************************/ +bool USBIsBusSuspended(void); +/*DOM-IGNORE-BEGIN*/ +#define USBIsBusSuspended() USBBusIsSuspended +/*DOM-IGNORE-END*/ + +/******************************************************************************* + Function: + void USBSoftDetach(void); + + Summary: + This function performs a detach from the USB bus via software. + + Description: + This function performs a detach from the USB bus via software. + + Conditions: + None + Input: + None + Return: + None + Remarks: + Caution should be used when detaching from the bus. Some PC drivers and + programs may require additional time after a detach before a device can be + reattached to the bus. + *****************************************************************************/ +void USBSoftDetach(void); +/*DOM-IGNORE-BEGIN*/ +#define USBSoftDetach() U1CON = 0; U1IE = 0; USBDeviceState = DETACHED_STATE; +/*DOM-IGNORE-END*/ + + +/************************************************************************* + Function: + bool USBHandleBusy(USB_HANDLE handle) + + Summary: + Checks to see if the input handle is busy + + Description: + Checks to see if the input handle is busy + + Typical Usage + + //make sure that the last transfer isn't busy by checking the handle + if(!USBHandleBusy(USBGenericInHandle)) + { + //Send the data contained in the INPacket[] array out on + // endpoint USBGEN_EP_NUM + USBGenericInHandle = USBGenWrite(USBGEN_EP_NUM,(uint8_t*)&INPacket[0],sizeof(INPacket)); + } + + + Conditions: + None + Input: + USB_HANDLE handle - handle of the transfer that you want to check the + status of + Return Values: + true - The specified handle is busy + false - The specified handle is free and available for a transfer + Remarks: + None + *************************************************************************/ +bool USBHandleBusy(USB_HANDLE handle); +/*DOM-IGNORE-BEGIN*/ +#if defined(__XC8__) + #define USBHandleBusy(handle) ((handle != 0x0000) && ((*(volatile uint8_t*)handle & _USIE) != 0x00)) +#else + #define USBHandleBusy(handle) (handle==0?0:((volatile BDT_ENTRY*)handle)->STAT.UOWN) +#endif +/*DOM-IGNORE-END*/ + +/******************************************************************** + Function: + uint16_t USBHandleGetLength(USB_HANDLE handle) + + Summary: + Retrieves the length of the destination buffer of the input + handle + + Description: + Retrieves the length of the destination buffer of the input + handle + + PreCondition: + None + + Parameters: + USB_HANDLE handle - the handle to the transfer you want the + address for. + + Return Values: + uint16_t - length of the current buffer that the input handle + points to. If the transfer is complete then this is the + length of the data transmitted or the length of data + actually received. + + Remarks: + None + + *******************************************************************/ +uint16_t USBHandleGetLength(USB_HANDLE handle); +/*DOM-IGNORE-BEGIN*/ +#define USBHandleGetLength(handle) (((volatile BDT_ENTRY*)handle)->CNT) +/*DOM-IGNORE-END*/ + +/******************************************************************** + Function: + uint16_t USBHandleGetAddr(USB_HANDLE) + + Summary: + Retrieves the address of the destination buffer of the input + handle + + Description: + Retrieves the address of the destination buffer of the input + handle + + PreCondition: + None + + Parameters: + USB_HANDLE handle - the handle to the transfer you want the + address for. + + Return Values: + uint16_t - address of the current buffer that the input handle + points to. + + Remarks: + None + + *******************************************************************/ +uint16_t USBHandleGetAddr(USB_HANDLE); +/*DOM-IGNORE-BEGIN*/ +#define USBHandleGetAddr(handle) ConvertToVirtualAddress((((volatile BDT_ENTRY*)handle)->ADR)) +/*DOM-IGNORE-END*/ + + +/******************************************************************** + Function: + USB_HANDLE USBGetNextHandle(uint8_t ep_num, uint8_t ep_dir) + Summary: + Retrieves the handle to the next endpoint BDT entry that the + USBTransferOnePacket() will use. + Description: + Retrieves the handle to the next endpoint BDT that the + USBTransferOnePacket() will use. Useful for initialization and when + ping pong buffering will be used on application endpoints. + PreCondition: + Will return NULL if the USB device has not yet been configured/the + endpoint specified has not yet been initialized by USBEnableEndpoint(). + Parameters: + uint8_t ep_num - The endpoint number to get the handle for (valid + values are 1-15, 0 is not a valid input value for this API) + uint8_t ep_dir - The endpoint direction associated with the endpoint number + to get the handle for (valid values are OUT_FROM_HOST and IN_TO_HOST). + Return Values: + USB_HANDLE - Returns the USB_HANDLE (a pointer) to the BDT that will be + used next time the USBTransferOnePacket() function is called, for the + given ep_num and ep_dir + Remarks: + This API is useful for initializing USB_HANDLEs during initialization of + the application firmware. It is also useful when ping-pong buffering is + enabled, and the application firmware wishes to arm both the even and odd + BDTs for an endpoint simultaneously. In this case, the application + firmware for sending data to the host would typically be something like + follows: + + + USB_HANDLE Handle1; + USB_HANDLE Handle2; + USB_HANDLE* pHandle = &Handle1; + uint8_t UserDataBuffer1[64]; + uint8_t UserDataBuffer2[64]; + uint8_t* pDataBuffer = &UserDataBuffer1[0]; + + //Add some code that loads UserDataBuffer1[] with useful data to send, + //using the pDataBuffer pointer, for example: + //for(i = 0; i < 64; i++) + //{ + // *pDataBuffer++ = [useful data value]; + //} + + //Check if the next USB endpoint BDT is available + if(!USBHandleBusy(USBGetNextHandle(ep_num, IN_TO_HOST)) + { + //The endpoint is available. Send the data. + *pHandle = USBTransferOnePacket(ep_num, ep_dir, pDataBuffer, bytecount); + //Toggle the handle and buffer pointer for the next transaction + if(pHandle == &Handle1) + { + pHandle = &Handle2; + pDataBuffer = &UserDataBuffer2[0]; + } + else + { + pHandle = &Handle1; + pDataBuffer = &UserDataBuffer1[0]; + } + } + + //The firmware can then load the next data buffer (in this case + //UserDataBuffer2)with useful data, and send it using the same + //process. For example: + + //Add some code that loads UserDataBuffer2[] with useful data to send, + //using the pDataBuffer pointer, for example: + //for(i = 0; i < 64; i++) + //{ + // *pDataBuffer++ = [useful data value]; + //} + + //Check if the next USB endpoint BDT is available + if(!USBHandleBusy(USBGetNextHandle(ep_num, IN_TO_HOST)) + { + //The endpoint is available. Send the data. + *pHandle = USBTransferOnePacket(ep_num, ep_dir, pDataBuffer, bytecount); + //Toggle the handle and buffer pointer for the next transaction + if(pHandle == &Handle1) + { + pHandle = &Handle2; + pDataBuffer = &UserDataBuffer2[0]; + } + else + { + pHandle = &Handle1; + pDataBuffer = &UserDataBuffer1[0]; + } + } + + + *******************************************************************/ +USB_HANDLE USBGetNextHandle(uint8_t ep_num, uint8_t ep_dir); +/*DOM-IGNORE-BEGIN*/ +#define USBGetNextHandle(ep_num, ep_dir) ((ep_dir == OUT_FROM_HOST)?((USB_HANDLE)pBDTEntryOut[ep_num]):((USB_HANDLE)pBDTEntryIn[ep_num])) +/*DOM-IGNORE-END*/ + +/******************************************************************** + Function: + void USBEP0Transmit(uint8_t options) + + Summary: + Sets the address of the data to send over the + control endpoint + + PreCondition: + None + + Parameters: + options - the various options that you want + when sending the control data. Options are: + USB_EP0_ROM + USB_EP0_RAM + USB_EP0_BUSY + USB_EP0_INCLUDE_ZERO + USB_EP0_NO_DATA + USB_EP0_NO_OPTIONS + + Return Values: + None + + Remarks: + None + + *******************************************************************/ +void USBEP0Transmit(uint8_t options); +/*DOM-IGNORE-BEGIN*/ +#define USBEP0Transmit(options) inPipes[0].info.Val = options | USB_EP0_BUSY +/*DOM-IGNORE-END*/ + +/************************************************************************* + Function: + void USBEP0SendRAMPtr(uint8_t* src, uint16_t size, uint8_t Options) + + Summary: + Sets the source, size, and options of the data you wish to send from a + RAM source + Conditions: + None + Input: + src - address of the data to send + size - the size of the data needing to be transmitted + options - the various options that you want when sending the control + data. Options are\: + * USB_EP0_ROM + * USB_EP0_RAM + * USB_EP0_BUSY + * USB_EP0_INCLUDE_ZERO + * USB_EP0_NO_DATA + * USB_EP0_NO_OPTIONS + Remarks: + None + *************************************************************************/ +void USBEP0SendRAMPtr(uint8_t* src, uint16_t size, uint8_t Options); +/*DOM-IGNORE-BEGIN*/ +#define USBEP0SendRAMPtr(src,size,options) {\ + inPipes[0].pSrc.bRam = src;\ + inPipes[0].wCount.Val = size;\ + inPipes[0].info.Val = options | USB_EP0_BUSY | USB_EP0_RAM;\ + } +/*DOM-IGNORE-END*/ + +/************************************************************************** + Function: + void USBEP0SendROMPtr(uint8_t* src, uint16_t size, uint8_t Options) + + Summary: + Sets the source, size, and options of the data you wish to send from a + const source + Conditions: + None + Input: + src - address of the data to send + size - the size of the data needing to be transmitted + options - the various options that you want when sending the control + data. Options are\: + * USB_EP0_ROM + * USB_EP0_RAM + * USB_EP0_BUSY + * USB_EP0_INCLUDE_ZERO + * USB_EP0_NO_DATA + * USB_EP0_NO_OPTIONS + Remarks: + None + **************************************************************************/ +void USBEP0SendROMPtr(uint8_t* src, uint16_t size, uint8_t Options); +/*DOM-IGNORE-BEGIN*/ +#define USBEP0SendROMPtr(src,size,options) {\ + inPipes[0].pSrc.bRom = src;\ + inPipes[0].wCount.Val = size;\ + inPipes[0].info.Val = options | USB_EP0_BUSY | USB_EP0_ROM;\ + } +/*DOM-IGNORE-END*/ + +/*************************************************************************** + Function: + void USBEP0Receive(uint8_t* dest, uint16_t size, void (*function)) + Summary: + Sets the destination, size, and a function to call on the completion of + the next control write. + Conditions: + None + Input: + dest - address of where the incoming data will go (make sure that this + address is directly accessible by the USB module for parts with + dedicated USB RAM this address must be in that space) + size - the size of the data being received (is almost always going to be + presented by the preceeding setup packet SetupPkt.wLength) + (*function) - a function that you want called once the data is received. If + this is specified as NULL then no function is called. + Remarks: + None + ***************************************************************************/ +void USBEP0Receive(uint8_t* dest, uint16_t size, void (*function)); +/*DOM-IGNORE-BEGIN*/ +#define USBEP0Receive(dest,size,function) {outPipes[0].pDst.bRam = dest;outPipes[0].wCount.Val = size;outPipes[0].pFunc = function;outPipes[0].info.bits.busy = 1; } +/*DOM-IGNORE-END*/ + +/******************************************************************** + Function: + USB_HANDLE USBTxOnePacket(uint8_t ep, uint8_t* data, uint16_t len) + + Summary: + Sends the specified data out the specified endpoint + + PreCondition: + None + + Parameters: + ep - the endpoint number you want to send the data out of + data - pointer to a user buffer that contains the data that you wish to + send to the host. Note: This RAM buffer must be accessible by + the USB module. + len - the number of bytes of data that you wish to send to the host, + in the next transaction on this endpoint. Note: this value + should always be less than or equal to the endpoint size, as + specified in the USB endpoint descriptor. + + Return Values: + USB_HANDLE - Returns a pointer to the BDT entry associated with the + transaction. The firmware can check for completion + of the transaction by using the USBHandleBusy() function, + using the returned USB_HANDLE value. + + Remarks: + None + + *******************************************************************/ +USB_HANDLE USBTxOnePacket(uint8_t ep, uint8_t* data, uint16_t len); +/*DOM-IGNORE-BEGIN*/ +#define USBTxOnePacket(ep,data,len) USBTransferOnePacket(ep,IN_TO_HOST,data,len) +/*DOM-IGNORE-END*/ + +/******************************************************************** + Function: + USB_HANDLE USBRxOnePacket(uint8_t ep, uint8_t* data, uint16_t len) + + Summary: + Receives the specified data out the specified endpoint + + PreCondition: + None + + Parameters: + ep - The endpoint number you want to receive the data on. + data - Pointer to a user buffer where the data will go when + it arrives from the host. Note: This RAM must be USB module + accessible. + len - The len parameter should always be set to the maximum endpoint packet + size, specified in the USB descriptor for this endpoint. The host + may send <= the number of bytes as the endpoint size in the endpoint + descriptor. After the transaction is complete, the application + firmware can call USBHandleGetLength() to determine how many bytes + the host actually sent in the last transaction on this endpoint. + + Return Values: + USB_HANDLE - Returns a pointer to the BDT entry associated with the + transaction. The firmware can check for completion + of the transaction by using the USBHandleBusy() function, + using the returned USB_HANDLE value. + + Remarks: + None + + *******************************************************************/ +USB_HANDLE USBRxOnePacket(uint8_t ep, uint8_t* data, uint16_t len); +/*DOM-IGNORE-BEGIN*/ +#define USBRxOnePacket(ep,data,len) USBTransferOnePacket(ep,OUT_FROM_HOST,data,len) +/*DOM-IGNORE-END*/ + +/******************************************************************************* + Function: + bool USB_APPLICATION_EVENT_HANDLER(uint8_t address, USB_EVENT event, void *pdata, uint16_t size); + + Summary: + This function is called whenever the USB stack wants to notify the user of + an event. + + Description: + This function is called whenever the USB stack wants to notify the user of + an event. This function should be implemented by the user. + + Example Usage: + Conditions: + None + + Input: + uint8_t address - the address of the device when the event happened + uint8_t event - The event input specifies which event happened. The + possible options are listed in the USB_DEVICE_STACK_EVENTS + enumeration. + + Return: + None + Remarks: + None + *****************************************************************************/ +bool USB_APPLICATION_EVENT_HANDLER(uint8_t address, USB_EVENT event, void *pdata, uint16_t size); + + + + +/************************************************************************** + Function: + void USBIncrement1msInternalTimers(void) + + Description: + This function increments internal 1ms time base counters, which are + useful for application code (that can use a 1ms time base/counter), and + for certain USB event timing specific purposes. + + In USB full speed applications, the application code does not need to (and should + not) explicitly call this function, as the USBDeviceTasks() function will + automatically call this function whenever a 1ms time interval has elapsed + (assuming the code is calling USBDeviceTasks() frequently enough in USB_POLLING + mode, or that USB interrupts aren't being masked for more than 1ms at a time + in USB_INTERRUPT mode). + + In USB low speed applications, the application firmware is responsible for + periodically calling this function at a ~1ms rate. This can be done using + a general purpose microcontroller timer set to interrupt every 1ms for example. + If the low speed application code does not call this function, the internal timers + will not increment, and the USBGet1msTickCount() API function will not be available. + Additionally, certain USB stack operations (like control transfer timeouts) + may be unavailable. + + Precondition: + This function should be called only after USBDeviceInit() has been + called (at least once at the start of the application). Ordinarily, + application code should never call this function, unless it is a low speed + USB device. + + Parameters: + None + + Return Values: + None + + Remarks: + This function does not need to be called during USB suspend conditions, when + the USB module/stack is disabled, or when the USB cable is detached from the host. + ***************************************************************************/ +void USBIncrement1msInternalTimers(void); + + +/************************************************************************** + Function: + uint32_t USBGet1msTickCount(void) + + Description: + This function retrieves a 32-bit unsigned integer that normally increments by + one every one millisecond. The count value starts from zero when the + USBDeviceInit() function is first called. See the remarks section for + details on special circumstances where the tick count will not increment. + + Precondition: + This function should be called only after USBDeviceInit() has been + called (at least once at the start of the application). + + Parameters: + None + + Return Values: + uint32_t representing the approximate millisecond count, since the time the + USBDeviceInit() function was first called. + + Remarks: + On 8-bit USB full speed devices, the internal counter is incremented on + every SOF packet detected. Therefore, it will not increment during suspend + or when the USB cable is detached. However, on 16-bit devices, the T1MSECIF + hardware interrupt source is used to increment the internal counter. Therefore, + on 16-bit devices, the count continue to increment during USB suspend or + detach events, so long as the application code has not put the microcontroller + to sleep during these events, and the application firmware is regularly + calling the USBDeviceTasks() function (or allowing it to execute, if using + USB_INTERRUPT mode operation). + + In USB low speed applications, the host does not broadcast SOF packets to + the device, so the application firmware becomes responsible for calling + USBIncrement1msInternalTimers() periodically (ex: from a general purpose + timer interrupt handler), or else the returned value from this function will + not increment. + + Prior to calling USBDeviceInit() for the first time the returned value will + be unpredictable. + + This function is USB_INTERRUPT mode safe and may be called from main loop + code without risk of retrieving a partially updated 32-bit number. + + However, this value only increments when the USBDeviceTasks() function is allowed + to execute. If USB_INTERRUPT mode is used, it is allowable to block on this + function. If however USB_POLLING mode is used, one must not block on this + function without also calling USBDeviceTasks() continuously for the blocking + duration (since the USB stack must still be allowed to execute, and the USB + stack is also responsible for updating the tick counter internally). + + If the application is operating in USB_POLLING mode, this function should + only be called from the main loop context, and not from an interrupt handler, + as the returned value could be incorrect, if the main loop context code was in + the process of updating the internal count at the moment of the interrupt event. + ***************************************************************************/ +uint32_t USBGet1msTickCount(void); + + + + +/************************************************************************** + Function: + uint8_t USBGetTicksSinceSuspendEnd(void); + + Description: + This function retrieves a 8-bit unsigned byte that represents the number + of milliseconds that have elapsed since the end of a USB suspend event. + The value saturates at 255. + + Precondition: + This function should be called only after USBDeviceInit() has been + called (at least once at the start of the application). + + Parameters: + None + + Return Values: + uint32_t representing the current millisecond count, since the time the + USBDeviceInit() function was first called, while the USB bus was non-suspended + and the device was attached to an active host. + + Remarks: + This function does not increment during USB suspend conditions, or when the USB + cable is detached from the host. Prior to calling USBDeviceInit() for the + first time the returned value will be unpredictable. + + This function is USB_INTERRUPT mode safe and may be called from main loop + code without risk of retrieving a partially updated 32-bit number. + + However, this value only increments when the USBDeviceTasks() function is allowed + to execute. If USB_INTERRUPT mode is used, it is allowable to block on this + function. If however USB_POLLING mode is used, one must not block on this + function without also calling USBDeviceTasks() continuously for the blocking + duration (since the USB stack must still be allowed to execute, and the USB + stack is also responsible for updating the tick counter internally). + ***************************************************************************/ +uint8_t USBGetTicksSinceSuspendEnd(void); +/*DOM-IGNORE-BEGIN*/ +#define USBGetTicksSinceSuspendEnd() USBTicksSinceSuspendEnd +/*DOM-IGNORE-END*/ + + + +/** Section: MACROS ******************************************************/ + +/* The DESC_CONFIG_WORD() macro is implemented for convenience. Since the + configuration descriptor array is a uint8_t array, each entry needs to be a + uint8_t in LSB format. The DESC_CONFIG_WORD() macro breaks up a uint16_t into + the appropriate uint8_t entries in LSB. + Typical Usage: + + const uint8_t configDescriptor1[]={ + 0x09, // Size of this descriptor in bytes + USB_DESCRIPTOR_CONFIGURATION, // CONFIGURATION descriptor type + DESC_CONFIG_WORD(0x0022), // Total length of data for this cfg + +*/ +#define DESC_CONFIG_WORD(a) (a&0xFF),((a>>8)&0xFF) + +/* The DESC_CONFIG_uint32_t() macro is implemented for convenience. Since the + configuration descriptor array is a uint8_t array, each entry needs to be a + uint8_t in LSB format. The DESC_CONFIG_uint32_t() macro breaks up a uint32_t into + the appropriate uint8_t entries in LSB. +*/ +#define DESC_CONFIG_uint32_t(a) (a&0xFF),((a>>8)&0xFF),((a>>16)&0xFF),((a>>24)&0xFF) + +/* The DESC_CONFIG_uint8_t() macro is implemented for convenience. The + DESC_CONFIG_uint8_t() macro provides a consistent macro for use with a byte + when generating a configuration descriptor when using either the + DESC_CONFIG_WORD() or DESC_CONFIG_uint32_t() macros. +*/ +#define DESC_CONFIG_uint8_t(a) (a) + + + + + + + + + + + + + + + + +/* DOM-IGNORE-BEGIN */ +/******************************************************************************* +******************************************************************************** +******************************************************************************** + This section contains implementation specific information that may vary + between releases as the implementation needs to change. This section is + included for compilation reasons only. +******************************************************************************** +******************************************************************************** +*******************************************************************************/ + +#if defined(USB_POLLING) + #define USB_VOLATILE +#else + #define USB_VOLATILE volatile +#endif + +#define CTRL_TRF_RETURN void +#define CTRL_TRF_PARAMS void + +typedef union +{ + uint16_t Val; + uint8_t v[2]; + struct + { + uint8_t LB; + uint8_t HB; + } byte; +} uint16_t_VAL; + +// Definition of the PIPE structure +// This structure is used to keep track of data that is sent out +// of the stack automatically. +typedef struct __attribute__ ((packed)) +{ + union __attribute__ ((packed)) + { + //Various options of pointers that are available to + // get the data from + uint8_t *bRam; + const uint8_t *bRom; + uint16_t *wRam; + const uint16_t *wRom; + }pSrc; + union __attribute__ ((packed)) + { + struct __attribute__ ((packed)) + { + //is this transfer from RAM or const? + uint8_t ctrl_trf_mem :1; + uint8_t reserved :5; + //include a zero length packet after + //data is done if data_size%ep_size = 0? + uint8_t includeZero :1; + //is this PIPE currently in use + uint8_t busy :1; + }bits; + uint8_t Val; + }info; + uint16_t_VAL __attribute__((aligned)) wCount; +}IN_PIPE; + +extern USB_VOLATILE IN_PIPE inPipes[]; + +typedef struct __attribute__ ((packed)) +{ + union __attribute__ ((packed)) + { + //Various options of pointers that are available to + // get the data from + uint8_t *bRam; + uint16_t *wRam; + }pDst; + union __attribute__ ((packed)) + { + struct __attribute__ ((packed)) + { + uint8_t reserved :7; + //is this PIPE currently in use + uint8_t busy :1; + }bits; + uint8_t Val; + }info; + uint16_t_VAL wCount; + CTRL_TRF_RETURN (*pFunc)(CTRL_TRF_PARAMS); +}OUT_PIPE; + +extern USB_VOLATILE bool RemoteWakeup; +extern USB_VOLATILE bool USBBusIsSuspended; +extern USB_VOLATILE USB_DEVICE_STATE USBDeviceState; +extern USB_VOLATILE uint8_t USBActiveConfiguration; +extern USB_VOLATILE uint8_t USBTicksSinceSuspendEnd; +/******************************************************************************/ +/* DOM-IGNORE-END */ + +#include + +#endif //USB_DEVICE_H diff --git a/inc/usb/usb_device_hid.h b/inc/usb/usb_device_hid.h new file mode 100644 index 0000000..6e0c3eb --- /dev/null +++ b/inc/usb/usb_device_hid.h @@ -0,0 +1,307 @@ +// DOM-IGNORE-BEGIN +/******************************************************************************* +Copyright 2015 Microchip Technology Inc. (www.microchip.com) + +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. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ +//DOM-IGNORE-END + +#ifndef HID_H +#define HID_H + + +/** INCLUDES *******************************************************/ + +#include "usb_ch9.h" + +/** DEFINITIONS ****************************************************/ + +/* Class-Specific Requests */ +#define GET_REPORT 0x01 +#define GET_IDLE 0x02 +#define GET_PROTOCOL 0x03 +#define SET_REPORT 0x09 +#define SET_IDLE 0x0A +#define SET_PROTOCOL 0x0B + +/* Class Descriptor Types */ +#define DSC_HID 0x21 +#define DSC_RPT 0x22 +#define DSC_PHY 0x23 + +/* Protocol Selection */ +#define BOOT_PROTOCOL 0x00 +#define RPT_PROTOCOL 0x01 + +/* HID Interface Class Code */ +#define HID_INTF 0x03 + +/* HID Interface Class SubClass Codes */ +#define BOOT_INTF_SUBCLASS 0x01 + +/* HID Interface Class Protocol Codes */ +#define HID_PROTOCOL_NONE 0x00 +#define HID_PROTOCOL_KEYBOARD 0x01 +#define HID_PROTOCOL_MOUSE 0x02 + +/******************************************************************** + Function: + void USBCheckHIDRequest(void) + + Summary: + This routine handles HID specific request that happen on EP0. + This function should be called from the USBCBCheckOtherReq() call back + function whenever implementing a HID device. + + Description: + This routine handles HID specific request that happen on EP0. These + include, but are not limited to, requests for the HID report + descriptors. This function should be called from the + USBCBCheckOtherReq() call back function whenever using an HID device. + + Typical Usage: + + void USBCBCheckOtherReq(void) + { + //Since the stack didn't handle the request I need to check + // my class drivers to see if it is for them + USBCheckHIDRequest(); + } + + + PreCondition: + None + + Parameters: + None + + Return Values: + None + + Remarks: + None + + *******************************************************************/ +void USBCheckHIDRequest(void); + +/******************************************************************** + Function: + bool HIDTxHandleBusy(USB_HANDLE handle) + + Summary: + Retrieves the status of the buffer ownership + + Description: + Retrieves the status of the buffer ownership. This function will + indicate if the previous transfer is complete or not. + + This function will take the input handle (pointer to a BDT entry) and + will check the UOWN bit. If the UOWN bit is set then that indicates + that the transfer is not complete and the USB module still owns the data + memory. If the UOWN bit is clear that means that the transfer is + complete and that the CPU now owns the data memory. + + For more information about the BDT, please refer to the appropriate + datasheet for the device in use. + + Typical Usage: + + //make sure that the last transfer isn't busy by checking the handle + if(!HIDTxHandleBusy(USBInHandle)) + { + //Send the data contained in the ToSendDataBuffer[] array out on + // endpoint HID_EP + USBInHandle = HIDTxPacket(HID_EP,(uint8_t*)&ToSendDataBuffer[0],sizeof(ToSendDataBuffer)); + } + + + PreCondition: + None. + + Parameters: + USB_HANDLE handle - the handle for the transfer in question. + The handle is returned by the HIDTxPacket() and HIDRxPacket() + functions. Please insure that USB_HANDLE objects are initialized + to NULL. + + Return Values: + TRUE - the HID handle is still busy + FALSE - the HID handle is not busy and is ready to send + additional data. + + Remarks: + None + + *******************************************************************/ +#define HIDTxHandleBusy(handle) USBHandleBusy(handle) + +/******************************************************************** + Function: + bool HIDRxHandleBusy(USB_HANDLE handle) + + Summary: + Retrieves the status of the buffer ownership + + Description: + Retrieves the status of the buffer ownership. This function will + indicate if the previous transfer is complete or not. + + This function will take the input handle (pointer to a BDT entry) and + will check the UOWN bit. If the UOWN bit is set then that indicates + that the transfer is not complete and the USB module still owns the data + memory. If the UOWN bit is clear that means that the transfer is + complete and that the CPU now owns the data memory. + + For more information about the BDT, please refer to the appropriate + datasheet for the device in use. + + Typical Usage: + + if(!HIDRxHandleBusy(USBOutHandle)) + { + //The data is available in the buffer that was specified when the + // HIDRxPacket() was called. + } + + + PreCondition: + None + + Parameters: + USB_HANDLE handle - the handle for the transfer in question. + The handle is returned by the HIDTxPacket() and HIDRxPacket() + functions. Please insure that USB_HANDLE objects are initialized + to NULL. + + Return Values: + TRUE - the HID handle is still busy + FALSE - the HID handle is not busy and is ready to receive + additional data. + + Remarks: + None + + *******************************************************************/ +#define HIDRxHandleBusy(handle) USBHandleBusy(handle) + +/******************************************************************** + Function: + USB_HANDLE HIDTxPacket(uint8_t ep, uint8_t* data, uint16_t len) + + Summary: + Sends the specified data out the specified endpoint + + Description: + This function sends the specified data out the specified + endpoint and returns a handle to the transfer information. + + Typical Usage: + + //make sure that the last transfer isn't busy by checking the handle + if(!HIDTxHandleBusy(USBInHandle)) + { + //Send the data contained in the ToSendDataBuffer[] array out on + // endpoint HID_EP + USBInHandle = HIDTxPacket(HID_EP,(uint8_t*)&ToSendDataBuffer[0],sizeof(ToSendDataBuffer)); + } + + + PreCondition: + None + + Parameters: + uint8_t ep - the endpoint you want to send the data out of + uint8_t* data - pointer to the data that you wish to send + uint16_t len - the length of the data that you wish to send + + Return Values: + USB_HANDLE - a handle for the transfer. This information + should be kept to track the status of the transfer + + Remarks: + None + + *******************************************************************/ +#define HIDTxPacket USBTxOnePacket + +/******************************************************************** + Function: + USB_HANDLE HIDRxPacket(uint8_t ep, uint8_t* data, uint16_t len) + + Summary: + Receives the specified data out the specified endpoint + + Description: + Receives the specified data out the specified endpoint. + + Typical Usage: + + //Read 64-uint8_ts from endpoint HID_EP, into the ReceivedDataBuffer array. + // Make sure to save the return handle so that we can check it later + // to determine when the transfer is complete. + USBOutHandle = HIDRxPacket(HID_EP,(uint8_t*)&ReceivedDataBuffer,64); + + + PreCondition: + None + + Parameters: + uint8_t ep - the endpoint you want to receive the data into + uint8_t* data - pointer to where the data will go when it arrives + uint16_t len - the length of the data that you wish to receive + + Return Values: + USB_HANDLE - a handle for the transfer. This information + should be kept to track the status of the transfer + + Remarks: + None + + *******************************************************************/ +#define HIDRxPacket USBRxOnePacket + +// Section: STRUCTURES *********************************************/ + +//USB HID Descriptor header as detailed in section +//"6.2.1 HID Descriptor" of the HID class definition specification +typedef struct _USB_HID_DSC_HEADER +{ + uint8_t bDescriptorType; //offset 9 + uint16_t wDscLength; //offset 10 +} USB_HID_DSC_HEADER; + +//USB HID Descriptor header as detailed in section +//"6.2.1 HID Descriptor" of the HID class definition specification +typedef struct _USB_HID_DSC +{ + uint8_t bLength; //offset 0 + uint8_t bDescriptorType; //offset 1 + uint16_t bcdHID; //offset 2 + uint8_t bCountryCode; //offset 4 + uint8_t bNumDsc; //offset 5 + + + //USB_HID_DSC_HEADER hid_dsc_header[HID_NUM_OF_DSC]; + /* HID_NUM_OF_DSC is defined in usbcfg.h */ + +} USB_HID_DSC; + +/** Section: EXTERNS ********************************************************/ +extern volatile CTRL_TRF_SETUP SetupPkt; +extern const uint8_t configDescriptor1[]; +extern volatile uint8_t CtrlTrfData[USB_EP0_BUFF_SIZE]; + +#endif //HID_H diff --git a/inc/usb/usb_device_local.h b/inc/usb/usb_device_local.h new file mode 100644 index 0000000..5c66f43 --- /dev/null +++ b/inc/usb/usb_device_local.h @@ -0,0 +1,424 @@ +// DOM-IGNORE-BEGIN +/******************************************************************************* +Copyright 2015 Microchip Technology Inc. (www.microchip.com) + +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. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ +//DOM-IGNORE-END + +#include "usb_config.h" + +/* Short Packet States - Used by Control Transfer Read - CTRL_TRF_TX */ +#define SHORT_PKT_NOT_USED 0 +#define SHORT_PKT_PENDING 1 +#define SHORT_PKT_SENT 2 + +/* Control Transfer States */ +#define WAIT_SETUP 0 +#define CTRL_TRF_TX 1 +#define CTRL_TRF_RX 2 + + +typedef union +{ + struct + { + unsigned char ping_pong_state :1; + unsigned char transfer_terminated :1; + } bits; + uint8_t Val; +} EP_STATUS; + +#if (USB_PING_PONG_MODE == USB_PING_PONG__NO_PING_PONG) + #define USB_NEXT_EP0_OUT_PING_PONG 0x0000 // Used in USB Device Mode only + #define USB_NEXT_EP0_IN_PING_PONG 0x0000 // Used in USB Device Mode only + #define USB_NEXT_PING_PONG 0x0000 // Used in USB Device Mode only + #define EP0_OUT_EVEN 0 // Used in USB Device Mode only + #define EP0_OUT_ODD 0 // Used in USB Device Mode only + #define EP0_IN_EVEN 1 // Used in USB Device Mode only + #define EP0_IN_ODD 1 // Used in USB Device Mode only + #define EP1_OUT_EVEN 2 // Used in USB Device Mode only + #define EP1_OUT_ODD 2 // Used in USB Device Mode only + #define EP1_IN_EVEN 3 // Used in USB Device Mode only + #define EP1_IN_ODD 3 // Used in USB Device Mode only + #define EP2_OUT_EVEN 4 // Used in USB Device Mode only + #define EP2_OUT_ODD 4 // Used in USB Device Mode only + #define EP2_IN_EVEN 5 // Used in USB Device Mode only + #define EP2_IN_ODD 5 // Used in USB Device Mode only + #define EP3_OUT_EVEN 6 // Used in USB Device Mode only + #define EP3_OUT_ODD 6 // Used in USB Device Mode only + #define EP3_IN_EVEN 7 // Used in USB Device Mode only + #define EP3_IN_ODD 7 // Used in USB Device Mode only + #define EP4_OUT_EVEN 8 // Used in USB Device Mode only + #define EP4_OUT_ODD 8 // Used in USB Device Mode only + #define EP4_IN_EVEN 9 // Used in USB Device Mode only + #define EP4_IN_ODD 9 // Used in USB Device Mode only + #define EP5_OUT_EVEN 10 // Used in USB Device Mode only + #define EP5_OUT_ODD 10 // Used in USB Device Mode only + #define EP5_IN_EVEN 11 // Used in USB Device Mode only + #define EP5_IN_ODD 11 // Used in USB Device Mode only + #define EP6_OUT_EVEN 12 // Used in USB Device Mode only + #define EP6_OUT_ODD 12 // Used in USB Device Mode only + #define EP6_IN_EVEN 13 // Used in USB Device Mode only + #define EP6_IN_ODD 13 // Used in USB Device Mode only + #define EP7_OUT_EVEN 14 // Used in USB Device Mode only + #define EP7_OUT_ODD 14 // Used in USB Device Mode only + #define EP7_IN_EVEN 15 // Used in USB Device Mode only + #define EP7_IN_ODD 15 // Used in USB Device Mode only + #define EP8_OUT_EVEN 16 // Used in USB Device Mode only + #define EP8_OUT_ODD 16 // Used in USB Device Mode only + #define EP8_IN_EVEN 17 // Used in USB Device Mode only + #define EP8_IN_ODD 17 // Used in USB Device Mode only + #define EP9_OUT_EVEN 18 // Used in USB Device Mode only + #define EP9_OUT_ODD 18 // Used in USB Device Mode only + #define EP9_IN_EVEN 19 // Used in USB Device Mode only + #define EP9_IN_ODD 19 // Used in USB Device Mode only + #define EP10_OUT_EVEN 20 // Used in USB Device Mode only + #define EP10_OUT_ODD 20 // Used in USB Device Mode only + #define EP10_IN_EVEN 21 // Used in USB Device Mode only + #define EP10_IN_ODD 21 // Used in USB Device Mode only + #define EP11_OUT_EVEN 22 // Used in USB Device Mode only + #define EP11_OUT_ODD 22 // Used in USB Device Mode only + #define EP11_IN_EVEN 23 // Used in USB Device Mode only + #define EP11_IN_ODD 23 // Used in USB Device Mode only + #define EP12_OUT_EVEN 24 // Used in USB Device Mode only + #define EP12_OUT_ODD 24 // Used in USB Device Mode only + #define EP12_IN_EVEN 25 // Used in USB Device Mode only + #define EP12_IN_ODD 25 // Used in USB Device Mode only + #define EP13_OUT_EVEN 26 // Used in USB Device Mode only + #define EP13_OUT_ODD 26 // Used in USB Device Mode only + #define EP13_IN_EVEN 27 // Used in USB Device Mode only + #define EP13_IN_ODD 27 // Used in USB Device Mode only + #define EP14_OUT_EVEN 28 // Used in USB Device Mode only + #define EP14_OUT_ODD 28 // Used in USB Device Mode only + #define EP14_IN_EVEN 29 // Used in USB Device Mode only + #define EP14_IN_ODD 29 // Used in USB Device Mode only + #define EP15_OUT_EVEN 30 // Used in USB Device Mode only + #define EP15_OUT_ODD 30 // Used in USB Device Mode only + #define EP15_IN_EVEN 31 // Used in USB Device Mode only + #define EP15_IN_ODD 31 // Used in USB Device Mode only + + #define EP(ep,dir,pp) (2*ep+dir) // Used in USB Device Mode only + #define BD(ep,dir,pp) ((8 * ep) + (4 * dir)) // Used in USB Device Mode only + +#elif (USB_PING_PONG_MODE == USB_PING_PONG__EP0_OUT_ONLY) + #define USB_NEXT_EP0_OUT_PING_PONG 0x0004 + #define USB_NEXT_EP0_IN_PING_PONG 0x0000 + #define USB_NEXT_PING_PONG 0x0000 + #define EP0_OUT_EVEN 0 + #define EP0_OUT_ODD 1 + #define EP0_IN_EVEN 2 + #define EP0_IN_ODD 2 + #define EP1_OUT_EVEN 3 + #define EP1_OUT_ODD 3 + #define EP1_IN_EVEN 4 + #define EP1_IN_ODD 4 + #define EP2_OUT_EVEN 5 + #define EP2_OUT_ODD 5 + #define EP2_IN_EVEN 6 + #define EP2_IN_ODD 6 + #define EP3_OUT_EVEN 7 + #define EP3_OUT_ODD 7 + #define EP3_IN_EVEN 8 + #define EP3_IN_ODD 8 + #define EP4_OUT_EVEN 9 + #define EP4_OUT_ODD 9 + #define EP4_IN_EVEN 10 + #define EP4_IN_ODD 10 + #define EP5_OUT_EVEN 11 + #define EP5_OUT_ODD 11 + #define EP5_IN_EVEN 12 + #define EP5_IN_ODD 12 + #define EP6_OUT_EVEN 13 + #define EP6_OUT_ODD 13 + #define EP6_IN_EVEN 14 + #define EP6_IN_ODD 14 + #define EP7_OUT_EVEN 15 + #define EP7_OUT_ODD 15 + #define EP7_IN_EVEN 16 + #define EP7_IN_ODD 16 + #define EP8_OUT_EVEN 17 + #define EP8_OUT_ODD 17 + #define EP8_IN_EVEN 18 + #define EP8_IN_ODD 18 + #define EP9_OUT_EVEN 19 + #define EP9_OUT_ODD 19 + #define EP9_IN_EVEN 20 + #define EP9_IN_ODD 20 + #define EP10_OUT_EVEN 21 + #define EP10_OUT_ODD 21 + #define EP10_IN_EVEN 22 + #define EP10_IN_ODD 22 + #define EP11_OUT_EVEN 23 + #define EP11_OUT_ODD 23 + #define EP11_IN_EVEN 24 + #define EP11_IN_ODD 24 + #define EP12_OUT_EVEN 25 + #define EP12_OUT_ODD 25 + #define EP12_IN_EVEN 26 + #define EP12_IN_ODD 26 + #define EP13_OUT_EVEN 27 + #define EP13_OUT_ODD 27 + #define EP13_IN_EVEN 28 + #define EP13_IN_ODD 28 + #define EP14_OUT_EVEN 29 + #define EP14_OUT_ODD 29 + #define EP14_IN_EVEN 30 + #define EP14_IN_ODD 30 + #define EP15_OUT_EVEN 31 + #define EP15_OUT_ODD 31 + #define EP15_IN_EVEN 32 + #define EP15_IN_ODD 32 + + #define EP(ep,dir,pp) (2u*ep+dir+(((ep==0)&&(dir==0))?pp:1)) + #define BD(ep,dir,pp) (4u*((2u*ep)+dir+(((ep==0)&&(dir==0))?pp:1))) + +#elif (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG) +#if defined (__18CXX) || defined(__C30__) || defined __XC16__ || defined(__XC8) + #if (defined (__dsPIC33E__) || defined (__PIC24E__)) + #define USB_NEXT_EP0_OUT_PING_PONG 0x0008 + #define USB_NEXT_EP0_IN_PING_PONG 0x0008 + #define USB_NEXT_PING_PONG 0x0008 + #else + #define USB_NEXT_EP0_OUT_PING_PONG 0x0004 + #define USB_NEXT_EP0_IN_PING_PONG 0x0004 + #define USB_NEXT_PING_PONG 0x0004 + #endif + #elif defined(__C32__) + #define USB_NEXT_EP0_OUT_PING_PONG 0x0008 + #define USB_NEXT_EP0_IN_PING_PONG 0x0008 + #define USB_NEXT_PING_PONG 0x0008 + #else + #error "Not defined for this compiler" + #endif + #define EP0_OUT_EVEN 0 + #define EP0_OUT_ODD 1 + #define EP0_IN_EVEN 2 + #define EP0_IN_ODD 3 + #define EP1_OUT_EVEN 4 + #define EP1_OUT_ODD 5 + #define EP1_IN_EVEN 6 + #define EP1_IN_ODD 7 + #define EP2_OUT_EVEN 8 + #define EP2_OUT_ODD 9 + #define EP2_IN_EVEN 10 + #define EP2_IN_ODD 11 + #define EP3_OUT_EVEN 12 + #define EP3_OUT_ODD 13 + #define EP3_IN_EVEN 14 + #define EP3_IN_ODD 15 + #define EP4_OUT_EVEN 16 + #define EP4_OUT_ODD 17 + #define EP4_IN_EVEN 18 + #define EP4_IN_ODD 19 + #define EP5_OUT_EVEN 20 + #define EP5_OUT_ODD 21 + #define EP5_IN_EVEN 22 + #define EP5_IN_ODD 23 + #define EP6_OUT_EVEN 24 + #define EP6_OUT_ODD 25 + #define EP6_IN_EVEN 26 + #define EP6_IN_ODD 27 + #define EP7_OUT_EVEN 28 + #define EP7_OUT_ODD 29 + #define EP7_IN_EVEN 30 + #define EP7_IN_ODD 31 + #define EP8_OUT_EVEN 32 + #define EP8_OUT_ODD 33 + #define EP8_IN_EVEN 34 + #define EP8_IN_ODD 35 + #define EP9_OUT_EVEN 36 + #define EP9_OUT_ODD 37 + #define EP9_IN_EVEN 38 + #define EP9_IN_ODD 39 + #define EP10_OUT_EVEN 40 + #define EP10_OUT_ODD 41 + #define EP10_IN_EVEN 42 + #define EP10_IN_ODD 43 + #define EP11_OUT_EVEN 44 + #define EP11_OUT_ODD 45 + #define EP11_IN_EVEN 46 + #define EP11_IN_ODD 47 + #define EP12_OUT_EVEN 48 + #define EP12_OUT_ODD 49 + #define EP12_IN_EVEN 50 + #define EP12_IN_ODD 51 + #define EP13_OUT_EVEN 52 + #define EP13_OUT_ODD 53 + #define EP13_IN_EVEN 54 + #define EP13_IN_ODD 55 + #define EP14_OUT_EVEN 56 + #define EP14_OUT_ODD 57 + #define EP14_IN_EVEN 58 + #define EP14_IN_ODD 59 + #define EP15_OUT_EVEN 60 + #define EP15_OUT_ODD 61 + #define EP15_IN_EVEN 62 + #define EP15_IN_ODD 63 + + #define EP(ep,dir,pp) (4*ep+2*dir+pp) + + #if defined (__18CXX) || defined(__C30__) || defined __XC16__ || (__XC8) + #if (defined(__dsPIC33E__) || defined (__PIC24E__)) + #define BD(ep,dir,pp) (8*(4*ep+2*dir+pp)) + #else + #define BD(ep,dir,pp) (4*(4*ep+2*dir+pp)) + #endif + #elif defined(__C32__) + #define BD(ep,dir,pp) (8*(4*ep+2*dir+pp)) + #else + #error "Not defined for this compiler" + #endif + +#elif (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0) + #define USB_NEXT_EP0_OUT_PING_PONG 0x0000 + #define USB_NEXT_EP0_IN_PING_PONG 0x0000 + #define USB_NEXT_PING_PONG 0x0004 + #define EP0_OUT_EVEN 0 + #define EP0_OUT_ODD 0 + #define EP0_IN_EVEN 1 + #define EP0_IN_ODD 1 + #define EP1_OUT_EVEN 2 + #define EP1_OUT_ODD 3 + #define EP1_IN_EVEN 4 + #define EP1_IN_ODD 5 + #define EP2_OUT_EVEN 6 + #define EP2_OUT_ODD 7 + #define EP2_IN_EVEN 8 + #define EP2_IN_ODD 9 + #define EP3_OUT_EVEN 10 + #define EP3_OUT_ODD 11 + #define EP3_IN_EVEN 12 + #define EP3_IN_ODD 13 + #define EP4_OUT_EVEN 14 + #define EP4_OUT_ODD 15 + #define EP4_IN_EVEN 16 + #define EP4_IN_ODD 17 + #define EP5_OUT_EVEN 18 + #define EP5_OUT_ODD 19 + #define EP5_IN_EVEN 20 + #define EP5_IN_ODD 21 + #define EP6_OUT_EVEN 22 + #define EP6_OUT_ODD 23 + #define EP6_IN_EVEN 24 + #define EP6_IN_ODD 25 + #define EP7_OUT_EVEN 26 + #define EP7_OUT_ODD 27 + #define EP7_IN_EVEN 28 + #define EP7_IN_ODD 29 + #define EP8_OUT_EVEN 30 + #define EP8_OUT_ODD 31 + #define EP8_IN_EVEN 32 + #define EP8_IN_ODD 33 + #define EP9_OUT_EVEN 34 + #define EP9_OUT_ODD 35 + #define EP9_IN_EVEN 36 + #define EP9_IN_ODD 37 + #define EP10_OUT_EVEN 38 + #define EP10_OUT_ODD 39 + #define EP10_IN_EVEN 40 + #define EP10_IN_ODD 41 + #define EP11_OUT_EVEN 42 + #define EP11_OUT_ODD 43 + #define EP11_IN_EVEN 44 + #define EP11_IN_ODD 45 + #define EP12_OUT_EVEN 46 + #define EP12_OUT_ODD 47 + #define EP12_IN_EVEN 48 + #define EP12_IN_ODD 49 + #define EP13_OUT_EVEN 50 + #define EP13_OUT_ODD 51 + #define EP13_IN_EVEN 52 + #define EP13_IN_ODD 53 + #define EP14_OUT_EVEN 54 + #define EP14_OUT_ODD 55 + #define EP14_IN_EVEN 56 + #define EP14_IN_ODD 57 + #define EP15_OUT_EVEN 58 + #define EP15_OUT_ODD 59 + #define EP15_IN_EVEN 60 + #define EP15_IN_ODD 61 + + #define EP(ep,dir,pp) (4*ep+2*dir+((ep==0)?0:(pp-2))) + #define BD(ep,dir,pp) (4*(4*ep+2*dir+((ep==0)?0:(pp-2)))) + +#else + #error "No ping pong mode defined." +#endif + +/****** Event callback enabling/disabling macros ******************** + This section of code is used to disable specific USB events that may not be + desired by the user. This can save code size and increase throughput and + decrease CPU utiliazation. +********************************************************************/ +#if defined USB_DISABLE_SUSPEND_HANDLER + #define USB_SUSPEND_HANDLER(event,pointer,size) + + #warning "Disabling the suspend handler is not recommended. Proper suspend handling is required to create a compliant USB device." +#else + #define USB_SUSPEND_HANDLER(event,pointer,size) USER_USB_CALLBACK_EVENT_HANDLER(event,pointer,size) +#endif + +#if defined USB_DISABLE_WAKEUP_FROM_SUSPEND_HANDLER + #define USB_WAKEUP_FROM_SUSPEND_HANDLER(event,pointer,size) + + #warning "Disabling the wake from suspend handler is not recommended. Proper suspend handling is required to create a compliant USB device." +#else + #define USB_WAKEUP_FROM_SUSPEND_HANDLER(event,pointer,size) USER_USB_CALLBACK_EVENT_HANDLER(event,pointer,size) +#endif + +#if defined USB_DISABLE_SOF_HANDLER + #define USB_SOF_HANDLER(event,pointer,size) +#else + #define USB_SOF_HANDLER(event,pointer,size) USER_USB_CALLBACK_EVENT_HANDLER(event,pointer,size) +#endif + +#if defined USB_DISABLE_TRANSFER_TERMINATED_HANDLER + #define USB_TRANSFER_TERMINATED_HANDLER(event,pointer,size) +#else + #define USB_TRANSFER_TERMINATED_HANDLER(event,pointer,size) USER_USB_CALLBACK_EVENT_HANDLER(event,pointer,size) +#endif + +#if defined USB_DISABLE_ERROR_HANDLER + #define USB_ERROR_HANDLER(event,pointer,size) +#else + #define USB_ERROR_HANDLER(event,pointer,size) USER_USB_CALLBACK_EVENT_HANDLER(event,pointer,size) +#endif + +#if defined USB_DISABLE_NONSTANDARD_EP0_REQUEST_HANDLER + #define USB_NONSTANDARD_EP0_REQUEST_HANDLER(event,pointer,size) +#else + #define USB_NONSTANDARD_EP0_REQUEST_HANDLER(event,pointer,size) USER_USB_CALLBACK_EVENT_HANDLER(event,pointer,size) +#endif + +#if defined USB_DISABLE_SET_DESCRIPTOR_HANDLER + #define USB_SET_DESCRIPTOR_HANDLER(event,pointer,size) +#else + #define USB_SET_DESCRIPTOR_HANDLER(event,pointer,size) USER_USB_CALLBACK_EVENT_HANDLER(event,pointer,size) +#endif + +#if defined USB_DISABLE_SET_CONFIGURATION_HANDLER + #define USB_SET_CONFIGURATION_HANDLER(event,pointer,size) +#else + #define USB_SET_CONFIGURATION_HANDLER(event,pointer,size) USER_USB_CALLBACK_EVENT_HANDLER(event,pointer,size) +#endif + +#if defined USB_DISABLE_TRANSFER_COMPLETE_HANDLER + #define USB_TRANSFER_COMPLETE_HANDLER(event,pointer,size) +#else + #define USB_TRANSFER_COMPLETE_HANDLER(event,pointer,size) USER_USB_CALLBACK_EVENT_HANDLER(event,pointer,size) +#endif + diff --git a/inc/usb/usb_hal.h b/inc/usb/usb_hal.h new file mode 100644 index 0000000..a6836e5 --- /dev/null +++ b/inc/usb/usb_hal.h @@ -0,0 +1,614 @@ +// DOM-IGNORE-BEGIN +/******************************************************************************* +Copyright 2015 Microchip Technology Inc. (www.microchip.com) + +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. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ +//DOM-IGNORE-END + +#ifndef _USB_HAL_H_ +#define _USB_HAL_H_ + +// ***************************************************************************** +// ***************************************************************************** +// Section: Included Files +// ***************************************************************************** +// ***************************************************************************** +#include + +#if defined(__18CXX) || defined(__XC8) + #if defined(_PIC14E) + #include "usb_hal_pic16f1.h" + #else + #include "usb_hal_pic18.h" + #endif +#elif defined(__C30__) || defined __XC16__ + #if defined(__dsPIC33E__) + #include "usb_hal_dspic33e.h" + #elif defined(__PIC24E__) + #include "usb_hal_pic24e.h" + #else + #include "usb_hal_pic24f.h" + #endif +#elif defined(__XC32__) + #if defined(__PIC32MM__) + #include "usb_hal_pic32mm.h" + #else + #error "Silicon Platform not defined" + #endif +#else + #error "Silicon Platform not defined" +#endif + +#ifdef __cplusplus // Provide C++ Compatability + extern "C" { +#endif + +// ***************************************************************************** +// ***************************************************************************** +// Section: Constants +// ***************************************************************************** +// ***************************************************************************** +/* USBHALControlUsbResistors flags */ +#define USB_HAL_PULL_UP_D_PLUS 0x80 // Pull D+ line high +#define USB_HAL_PULL_UP_D_MINUS 0x40 // Pull D- line high +#define USB_HAL_PULL_DN_D_PLUS 0x20 // Pull D+ line low +#define USB_HAL_PULL_DN_D_MINUS 0x10 // Pull D- line low +/* + The following are defined for convenience: + */ +#define USB_HAL_DEV_CONN_FULL_SPD USB_HAL_PULL_UP_D_PLUS +#define USB_HAL_DEV_CONN_LOW_SPD USB_HAL_PULL_UP_D_MINUS +#define USB_HAL_DEV_DISCONNECT 0 + +/* USBHALControlBusPower Commands */ +#define USB_VBUS_DISCHARGE 0 // Dicharge Vbus via resistor +#define USB_VBUS_CHARGE 1 // Charge Vbus via resistor +#define USB_VBUS_POWER_ON 3 // Supply power to Vbus +#define USB_VBUS_POWER_OFF 4 // Do not supply power to Vbus + +/* + USBHALGetLastError Error Bits. + */ +#define USBHAL_PID_ERR 0x00000001 // Packet ID Error +#define USBHAL_CRC5 0x00000002 // (Host) Token CRC5 check failed +#define USBHAL_HOST_EOF 0x00000002 // (Host) EOF not reached before next SOF +#define USBHAL_CRC16 0x00000004 // Data packet CRC error +#define USBHAL_DFN8 0x00000008 // Data field size not n*8 bits +#define USBHAL_BTO_ERR 0x00000010 // Bus turn-around timeout +#define USBHAL_DMA_ERR 0x00000020 // DMA error, unable to read/write memory +#define USBHAL_BTS_ERR 0x00000080 // Bit-stuffing error +#define USBHAL_XFER_ID 0x00000100 // Unable to identify transfer EP +#define USBHAL_NO_EP 0x00000200 // Invalid endpoint number +#define USBHAL_DMA_ERR2 0x00000400 // Error starting DMA transaction + +/* Flags for USBHALSetEpConfiguration */ +#if defined(__18CXX) || defined(__XC8) + #define USB_HAL_TRANSMIT 0x0400 // Enable EP for transmitting data + #define USB_HAL_RECEIVE 0x0200 // Enable EP for receiving data + #define USB_HAL_HANDSHAKE 0x1000 // Enable EP to give ACK/NACK (non isoch) + + #define USB_HAL_NO_INC 0x0010 // Use for DMA to another device FIFO + #define USB_HAL_HW_KEEPS 0x0020 // Cause HW to keep EP +#else + #define USB_HAL_TRANSMIT 0x0400 // Enable EP for transmitting data + #define USB_HAL_RECEIVE 0x0800 // Enable EP for receiving data + #define USB_HAL_HANDSHAKE 0x0100 // Enable EP to give ACK/NACK (non isoch) + + /* Does not work, Fix this if needed. 3/1/07 - Bud + #define USB_HAL_NO_INC 0x0010 // Use for DMA to another device FIFO + #define USB_HAL_HW_KEEPS 0x0020 // Cause HW to keep EP + */ + #define USB_HAL_ALLOW_HUB 0x8000 // (host only) Enable low-spd hub support + #define USB_HAL_NO_RETRY 0x4000 // (host only) disable auto-retry on NACK +#endif +// ***************************************************************************** +// ***************************************************************************** +// Section: Data Types +// ***************************************************************************** +// ***************************************************************************** + + +// ***************************************************************************** +// ***************************************************************************** +// Section: Interface Routines +// ***************************************************************************** +// ***************************************************************************** + +/************************************************************************* + Function: + void USBHALSetBusAddress( uint8_t addr ) + + Description: + This routine sets the address of the system on the USB + when acting as a peripheral device. + + Preconditions: + 1. USBHALInitialize must have been called to + initialize the USB HAL. + 2. Endpoint zero (0) must be configured as appropriate + by calls to USBHALSetEpConfiguration. + 3. The system must have been enumerated on the USB (as + a device). + + Parameters: + addr Desired address of this device on the USB. + + Return Values: + None + + Side Effect: + The bus address has been set. + + Remarks: + The address is assigned by the host and is received in + a SET_ADDRESS setup request. + + *************************************************************************/ +/* + This routine is implemented as a macro to a lower-level level routine. + */ + +#define USBHALSetBusAddress OTGCORE_SetDeviceAddr + +void USBHALSetBusAddress( uint8_t addr ); + + +/************************************************************************* + Function: + void USBHALControlUsbResistors( uint8_t flags ); + + Description: + This routine enables or disables the USB pull-up or + pull-down resistors as requested. + + Precondition: + USBInitialize must have been called to initialize the + USB SW stack. + + Parameters: + flags - This is a bit-mapped flags value indicating + which resistors to enable or disable (see below). + + Return Values: + true if successful, false if not. + + Side Effects: + The resistors are enabled as requested. + + Remarks: + Used for USB peripheral control to connect to or + disconnect from the bus. Otherwise, used for OTG + SRP/HNP and host support. + + *************************************************************************/ + +/* + This routine is implemented as a macro to a lower-level level routine. + */ + #if defined(__18CXX) || defined(__XC8) + void USBHALControlUsbResistors( uint8_t flags ); + #else + #define USBHALControlUsbResistors OTGCORE_ControlUsbResistors + void USBHALControlUsbResistors( uint8_t flags ); +#endif + +/* + MCHP: Define a method to check for SE0 & a way to send a reset (SE0). + */ + + +/************************************************************************* + Function: + bool USBHALSessionIsValid( void ) + + Description: + This routine determines if there is currently a valid + USB session or not. + + Precondition: + USBInitialize must have been called to initialize the + USB SW stack. + + Parameters: + None + + Return Values: + true if the session is currently valid, false if not. + + Remarks: + Only used for host and OTG support. + + *************************************************************************/ + +bool USBHALSessionIsValid( void ); + + +/************************************************************************* + Function: + USBHALControlBusPower + + Description: + This routine provides a bitmap of the most recent + error conditions to occur. + + Precondition: + USBInitialize must have been called to initialize the + USB SW stack. + + Parameters: + cmd - Identifies desired command (see below). + + Return Values: + true if successful, false if not. + + Remarks: + Only used for host and OTG support. + + *************************************************************************/ + +bool USBHALControlBusPower( uint8_t cmd ); + +/************************************************************************* + Function: + unsigned long USBHALGetLastError( void ) + + Description: + This routine provides a bitmap of the most recent + error conditions to occur. + + Precondition: + USBInitialize must have been called to initialize the + USB SW stack. + + Parameters: + None + + Return Values: + Bitmap indicating the most recent error condition(s). + + Side Effect: + Error record is cleared. + + Remarks: + Although record of the error state is cleared, nothing + is done to fix the condition or recover from the + error. The client must take appropriate steps. + + *************************************************************************/ + +unsigned long USBHALGetLastError( void ); + + + + +/************************************************************************* + Function: + void USBHALHandleBusEvent ( void ) + + Description: + This routine checks the USB for any events that may + have occurred and handles them appropriately. It may + be called directly to poll the USB and handle events + or it may be called in response to an interrupt. + + Precondition: + USBInitialize must have been called to initialize the + USB SW stack. + + Parameters: + None + + Return Values: + None + + Side Effects: + Depend on the event that may have occurred. + + Remarks: + None + + *************************************************************************/ + +void USBHALHandleBusEvent ( void ); + + +/************************************************************************* + Function: + bool USBHALStallPipe( TRANSFER_FLAGS pipe ) + + Description: + This routine stalls the given endpoint. + + Preconditions: + USBHALInitialize must have been called to initialize + the USB HAL. + + Parameters: + pipe - Uses the TRANSFER_FLAGS (see USBCommon.h) format to + identify the endpoint and direction making up the + pipe to stall. + + Note: Only ep_num and direction fields are required. + + Return Values: + true if able to stall endpoint, false if not. + + Side Effects: + The endpoint will stall if additional data transfer is + attempted. + Given endpoint has been stalled. + + Remarks: + Starting another data transfer automatically + "un-stalls" the endpoint. + + *************************************************************************/ +/* + Note: This function is implemented as a macro, calling directly into + an internal HAL routine. + */ + +#define USBHALStallPipe OTGCORE_StallPipe + +bool USBHALStallPipe( TRANSFER_FLAGS pipe ); + + +/****************************************************************************** + Function: + bool USBHALUnstallPipe( TRANSFER_FLAGS pipe ) + + Description: + This routine clears the stall condition for the given pipe. + + PreCondition: + Assumes OTGCORE_DeviceEnable has been called and + OTGCORE_StallPipe has been called on the given pipe. + + Parameters: + pipe - Uses the TRANSFER_FLAGS (see USBCommon.h) format to + identify the endpoint and direction making up the + pipe to un-stall. + + Return Values: + true if able to stall the pipe, false if not. + + Side Effects: + The BSTALL and UOWN bits (and all other control bits) in + the BDT for the given pipe will be cleared. + + Remarks: + None + + *****************************************************************************/ +/* + Note: This function is implemented as a macro, calling directly into + an internal HAL routine. + */ + +#define USBHALUnstallPipe OTGCORE_UnstallPipe + +bool USBHALUnstallPipe( TRANSFER_FLAGS pipe ); + + +/************************************************************************** + Function: + USBHALGetStalledEndpoints + + Description: + This function returns a 16-bit bit-mapped value with a + bit set in the position of any endpoint that is stalled + (i.e. if endpoint 0 is stalled then bit 0 is set, if + endpoint 1 is stalled then bit 1 is set, etc.). + + Preconditions: + USBHALInitialize must have been called to initialize + the USB HAL. + + Parameters: + None + + Return Values: + Bitmap of the currently stalled endpoints (see overview). + + Remarks: + None + *************************************************************************/ + +/* + Note: This function is implemented as a macro, calling directly into + a HAL routine. + */ + +#define USBHALGetStalledEndpoints OTGCORE_GetStalledEndpoints + +uint16_t USBHALGetStalledEndpoints ( void ); + + +/****************************************************************************** + Function: + bool USBHALFlushPipe( TRANSFER_FLAGS pipe ) + + Description: + This routine clears any pending transfers on the given + pipe. + + Preconditions: + USBHALInitialize must have been called to initialize the + USB HAL. + + The caller must ensure that there is no possible way for + hardware to be currently accessing the pipe (see notes). + + Parameters: + pipe - Uses the TRANSFER_FLAGS (see USBCommon.h) format to + identify the endpoint and direction making up the + pipe to flush. + + Return Values: + true if successful, false if not. + + Side Effects: + Transfer data for this pipe has been zeroed out. + + Remarks: + This routine ignores the normal HW protocol for ownership + of the pipe data and flushes the pipe, even if it is in + process. Thus, the caller must ensure that data transfer + cannot be in process. This situation occurs when a + transfer has been terminated early by the host. + *****************************************************************************/ + +bool USBHALFlushPipe( TRANSFER_FLAGS pipe ); + + +/************************************************************************** + Function: + USBHALTransferData + + Description: + This routine prepares to transfer data on the USB. + If the system is in device mode, the actual transfer + will not occur until the host performs an OUT request + to the given endpoint. If the system is in host mode, + the transfer will not start until the token has been + sent on the bus. + + Preconditions: + 1. USBHALInitialize must have been called to + initialize the USB HAL. + 2. The endpoint through which the data will be + transferred must be configured as appropriate by a + call to USBHALSetEpConfiguration. + 3. The bus must have been enumerated (either as a host + or device). Except for EP0 transfers. + + Parameters: + flags - Flags consists of the endpoint number OR'd + with one or more flags indicating transfer + direction and such (see "Data Transfer + Macros" in USBCommon.h): + + 7 6 5 4 3 2 1 0 - Description + | | | | \_____/ + | | | | +----- Endpoint Number + | | | +---------- Short or zero-size packet + | | +------------ Data Toggle 0/1 + | +-------------- Force Data Toggle + +---------------- 1=Transmit/0=Receive + + buffer Address of the buffer to receive data. + + size Number of uint8_ts of data to transfer. + + Return Values: + true if the HAL was able to successfully start the + data transfer, false if not. + + Side Effects: + The HAL has prepared to transfer the data on the USB. + + Remarks: + The HAL will continue the data transfer, keeping track + of the buffer address, data remaining, and ping-pong + buffer details internally when USBHALHandleBusEvent is + called (either polled or in response to an interrupt). + The caller will receive notification that the transfer + has completed when the EVT_XFER event is passed into + the USBHALBusEventCallout call-out function. + + *************************************************************************/ + +bool USBHALTransferData ( TRANSFER_FLAGS flags, + void *buffer, + unsigned int size ); + + +/************************************************************************* + Function: + USBHALSetEpConfiguration + + Description: + This routine allows the caller to configure various + options (see "Flags for USBHALSetEpConfiguration", + below) and set the behavior for the given endpoint. + + Precondition: + USBHALInitialize has been called. + + Parameters: + ep_num - Number of endpoint to configure, Must be + (ep_num >=0) && (ep_num <= USB_DEV_HIGHEST_EP_NUMBER) + max_pkt_size Size of largest packet this enpoint can + transfer. + + flags - Configuration flags (see below) + + Return Values: + true if successful, false if not. + + Side Effects: + The endpoint has been configured as desired. + + Remarks: + The base address and size of the buffer is not set by + this routine. Those features of an endpoint are + dynamically managed by the USBHALTransferData routine. + An endpoint can be "de-configured" by setting its max + packet size to 0. When doing this, you should also + set all flags to 0. + *************************************************************************/ + +bool USBHALSetEpConfiguration ( uint8_t ep_num, uint16_t max_pkt_size, uint16_t flags ); + +/************************************************************************* + Function: + USBHALInitialize + + Description: + This call performs the basic initialization of the USB + HAL. This routine must be called before any of the + other HAL interface routines are called. + + Precondition: + The system has been initialized. + + Parameters: + flags - Initialization flags + + Return Values: + true if successful, false if not. + + Side Effects: + The USB HAL SW stack was initialized. + + Remarks: + This routine can be called to reset the controller. + + *************************************************************************/ + +bool USBHALInitialize ( unsigned long flags ); + + +#ifdef __cplusplus // Provide C++ Compatibility + } +#endif + +#endif // _USB_HAL_H_ +/************************************************************************* + * EOF + */ + diff --git a/inc/usb/usb_hal_pic18.h b/inc/usb/usb_hal_pic18.h new file mode 100644 index 0000000..b666a71 --- /dev/null +++ b/inc/usb/usb_hal_pic18.h @@ -0,0 +1,611 @@ +// DOM-IGNORE-BEGIN +/******************************************************************************* +Copyright 2015 Microchip Technology Inc. (www.microchip.com) + +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. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ +//DOM-IGNORE-END + +#ifndef _USB_HAL_PIC18_H +#define _USB_HAL_PIC18_H + +// ***************************************************************************** +// ***************************************************************************** +// Section: Included Files +// ***************************************************************************** +// ***************************************************************************** +/* This section lists the other files that are included in this file. +*/ +#if defined(__XC8) + #include + #include +#elif defined(__C18) + #include + #ifndef uint8_t + #define uint8_t unsigned char + #endif + #ifndef uint16_t + #define uint16_t unsigned int + #endif + #ifndef uint32_t + #define uint32_t unsigned long int + #endif +#endif + +#include + +#include "usb_config.h" + +#ifdef __cplusplus // Provide C++ Compatability + extern "C" { +#endif + +// ***************************************************************************** +// ***************************************************************************** +// Section: Constants +// ***************************************************************************** +// ***************************************************************************** +#define USB_HAL_VBUSTristate() //No dedicated VBUS pin on these devices. + +//----- USBEnableEndpoint() input definitions ---------------------------------- +#define USB_HANDSHAKE_ENABLED 0x10 +#define USB_HANDSHAKE_DISABLED 0x00 + +#define USB_OUT_ENABLED 0x04 +#define USB_OUT_DISABLED 0x00 + +#define USB_IN_ENABLED 0x02 +#define USB_IN_DISABLED 0x00 + +#define USB_ALLOW_SETUP 0x00 +#define USB_DISALLOW_SETUP 0x08 + +#define USB_STALL_ENDPOINT 0x01 + +//----- usb_config.h input definitions ----------------------------------------- +#define USB_PULLUP_ENABLE 0x10 +#define USB_PULLUP_DISABLED 0x00 + +#define USB_INTERNAL_TRANSCEIVER 0x00 +#define USB_EXTERNAL_TRANSCEIVER 0x08 + +#define USB_FULL_SPEED 0x04 +#define USB_LOW_SPEED 0x00 + +//----- Interrupt Flag definitions -------------------------------------------- +#define USBTransactionCompleteIE UIEbits.TRNIE +#define USBTransactionCompleteIF UIRbits.TRNIF +#define USBTransactionCompleteIFReg UIR +#define USBTransactionCompleteIFBitNum 0xF7 //AND mask for clearing TRNIF bit position 4 + +#define USBResetIE UIEbits.URSTIE +#define USBResetIF UIRbits.URSTIF +#define USBResetIFReg UIR +#define USBResetIFBitNum 0xFE //AND mask for clearing URSTIF bit position 0 + +#define USBIdleIE UIEbits.IDLEIE +#define USBIdleIF UIRbits.IDLEIF +#define USBIdleIFReg UIR +#define USBIdleIFBitNum 0xEF //AND mask for clearing IDLEIF bit position 5 + +#define USBActivityIE UIEbits.ACTVIE +#define USBActivityIF UIRbits.ACTVIF +#define USBActivityIFReg UIR +#define USBActivityIFBitNum 0xFB //AND mask for clearing ACTVIF bit position 2 + +#define USBSOFIE UIEbits.SOFIE +#define USBSOFIF UIRbits.SOFIF +#define USBSOFIFReg UIR +#define USBSOFIFBitNum 0xBF //AND mask for clearing SOFIF bit position 6 + +#define USBStallIE UIEbits.STALLIE +#define USBStallIF UIRbits.STALLIF +#define USBStallIFReg UIR +#define USBStallIFBitNum 0xDF //AND mask for clearing STALLIF bit position 5 + +#define USBErrorIE UIEbits.UERRIE +#define USBErrorIF UIRbits.UERRIF +#define USBErrorIFReg UIR +#define USBErrorIFBitNum 0xFD //UERRIF bit position 1. Note: This bit is read only and is cleared by clearing the enabled UEIR flags + +//----- Event call back defintions -------------------------------------------- +#if defined(USB_DISABLE_SOF_HANDLER) + #define USB_SOF_INTERRUPT 0x00 +#else + #define USB_SOF_INTERRUPT 0x40 +#endif + +#if defined(USB_DISABLE_ERROR_HANDLER) + #define USB_ERROR_INTERRUPT 0x02 +#else + #define USB_ERROR_INTERRUPT 0x02 +#endif + +//----- USB module control bits ----------------------------------------------- +#define USBPingPongBufferReset UCONbits.PPBRST +#define USBSE0Event UCONbits.SE0 +#define USBSuspendControl UCONbits.SUSPND +#define USBPacketDisable UCONbits.PKTDIS +#define USBResumeControl UCONbits.RESUME + +//----- BDnSTAT bit definitions ----------------------------------------------- +#define _BSTALL 0x04 //Buffer Stall enable +#define _DTSEN 0x08 //Data Toggle Synch enable +#define _INCDIS 0x10 //Address increment disable +#define _KEN 0x20 //SIE keeps buff descriptors enable +#define _DAT0 0x00 //DATA0 packet expected next +#define _DAT1 0x40 //DATA1 packet expected next +#define _DTSMASK 0x40 //DTS Mask +#define _USIE 0x80 //SIE owns buffer +#define _UCPU 0x00 //CPU owns buffer +#define _STAT_MASK 0xFF + +#define USTAT_EP0_PP_MASK ~0x02 +#define USTAT_EP_MASK 0x7E +#define USTAT_EP0_OUT 0x00 +#define USTAT_EP0_OUT_EVEN 0x00 +#define USTAT_EP0_OUT_ODD 0x02 +#define USTAT_EP0_IN 0x04 +#define USTAT_EP0_IN_EVEN 0x04 +#define USTAT_EP0_IN_ODD 0x06 + +#define ENDPOINT_MASK 0b01111000 + +//----- U1EP bit definitions -------------------------------------------------- +#define UEP_STALL 0x0001 +// Cfg Control pipe for this ep +/* Endpoint configuration options for USBEnableEndpoint() function */ +#define EP_CTRL 0x06 // Cfg Control pipe for this ep +#define EP_OUT 0x0C // Cfg OUT only pipe for this ep +#define EP_IN 0x0A // Cfg IN only pipe for this ep +#define EP_OUT_IN 0x0E // Cfg both OUT & IN pipes for this ep + +//----- Remap the PIC18 register name space------------------------------------ +#define U1ADDR UADDR +#define U1IE UIE +#define U1IR UIR +#define U1EIR UEIR +#define U1EIE UEIE +#define U1CON UCON +#define U1EP0 UEP0 +#define U1CONbits UCONbits +#define U1EP1 UEP1 +#define U1CNFG1 UCFG +#define U1STAT USTAT +#define U1EP0bits UEP0bits + +//----- Defintions for BDT address -------------------------------------------- +#if defined(__16F1454) || defined(__16F1455) || defined(__16F1459) || defined(__16LF1454) || defined(__16LF1455) || defined(__16LF1459) + #define USB_BDT_ADDRESS 0x020 +#elif defined(__18F14K50) || defined(__18F13K50) || defined(__18LF14K50) || defined(__18LF13K50) + #define USB_BDT_ADDRESS 0x200 //See Linker Script, BDT in bank 2 on these devices - usb2:0x200-0x2FF(256-byte) +#elif defined(__18F24K50) || defined(__18F25K50) || defined(__18F45K50) || defined(__18LF24K50) || defined(__18LF25K50) || defined(__18LF45K50) + #define USB_BDT_ADDRESS 0x400 //See Linker Script, BDT in bank 4 +#elif defined(__18F47J53) || defined(__18F46J53) || defined(__18F27J53) || defined(__18F26J53) || defined(__18LF47J53) || defined(__18LF46J53) || defined(__18LF27J53) || defined(__18LF26J53) + #define USB_BDT_ADDRESS 0xD00 //BDT in Bank 13 on these devices +#elif defined(__18F97J94) || defined(__18F87J94) || defined(__18F67J94) || defined(__18F96J94) || defined(__18F86J94) || defined(__18F66J94) || defined(__18F96J99) || defined(__18F95J94) || defined(__18F86J99) || defined(__18F85J94) || defined(__18F66J99) || defined(__18F65J94) + #define USB_BDT_ADDRESS 0x100 //BDT in Bank 1 on these devices +#else + #define USB_BDT_ADDRESS 0x400 //All other PIC18 devices place the BDT in usb4:0x400-0x4FF(256-byte) +#endif + +#if (USB_PING_PONG_MODE == USB_PING_PONG__NO_PING_PONG) + #define BDT_NUM_ENTRIES ((USB_MAX_EP_NUMBER + 1) * 2) +#elif (USB_PING_PONG_MODE == USB_PING_PONG__EP0_OUT_ONLY) + #define BDT_NUM_ENTRIES (((USB_MAX_EP_NUMBER + 1) * 2)+1) +#elif (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG) + #define BDT_NUM_ENTRIES ((USB_MAX_EP_NUMBER + 1) * 4) +#elif (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0) + #define BDT_NUM_ENTRIES (((USB_MAX_EP_NUMBER + 1) * 4)-2) +#else + #error "No ping pong mode defined." +#endif + +#if defined(__XC8) + #define CTRL_TRF_SETUP_ADDRESS (USB_BDT_ADDRESS+(BDT_NUM_ENTRIES*4)) + #define CTRL_TRF_DATA_ADDRESS (CTRL_TRF_SETUP_ADDRESS + USB_EP0_BUFF_SIZE) + + #define BDT_BASE_ADDR_TAG @USB_BDT_ADDRESS + #define CTRL_TRF_SETUP_ADDR_TAG @CTRL_TRF_SETUP_ADDRESS + #define CTRL_TRF_DATA_ADDR_TAG @CTRL_TRF_DATA_ADDRESS + + #if defined(USB_USE_MSD) + //MSD application specific USB endpoint buffer placement macros (so they + //get linked to a USB module accessible portion of RAM) + #define MSD_CBW_ADDRESS (CTRL_TRF_DATA_ADDRESS + USB_EP0_BUFF_SIZE) + #define MSD_CSW_ADDRESS (MSD_CBW_ADDRESS + MSD_OUT_EP_SIZE) + #define MSD_CBW_ADDR_TAG @MSD_CBW_ADDRESS + #define MSD_CSW_ADDR_TAG @MSD_CSW_ADDRESS + #endif +#else + #define BDT_BASE_ADDR_TAG __attribute__ ((aligned (512))) + #define CTRL_TRF_SETUP_ADDR_TAG + #define CTRL_TRF_DATA_ADDR_TAG + #define MSD_CBW_ADDR_TAG + #define MSD_CSW_ADDR_TAG +#endif + +//----- Deprecated definitions - will be removed at some point of time---------- +//--------- Deprecated in v2.2 +#define _LS 0x00 // Use Low-Speed USB Mode +#define _FS 0x04 // Use Full-Speed USB Mode +#define _TRINT 0x00 // Use internal transceiver +#define _TREXT 0x08 // Use external transceiver +#define _PUEN 0x10 // Use internal pull-up resistor +#define _OEMON 0x40 // Use SIE output indicator + +// ***************************************************************************** +// ***************************************************************************** +// Section: Data Types +// ***************************************************************************** +// ***************************************************************************** + +// Buffer Descriptor Status Register layout. +typedef union _BD_STAT +{ + uint8_t Val; + struct{ + //If the CPU owns the buffer then these are the values + unsigned BC8:1; //bit 8 of the byte count + unsigned BC9:1; //bit 9 of the byte count + unsigned BSTALL:1; //Buffer Stall Enable + unsigned DTSEN:1; //Data Toggle Synch Enable + unsigned INCDIS:1; //Address Increment Disable + unsigned KEN:1; //BD Keep Enable + unsigned DTS:1; //Data Toggle Synch Value + unsigned UOWN:1; //USB Ownership + }; + struct{ + //if the USB module owns the buffer then these are + // the values + unsigned :2; + unsigned PID0:1; //Packet Identifier + unsigned PID1:1; + unsigned PID2:1; + unsigned PID3:1; + unsigned :1; + }; + struct{ + unsigned :2; + unsigned PID:4; //Packet Identifier + unsigned :2; + }; +} BD_STAT; //Buffer Descriptor Status Register + +// BDT Entry Layout +typedef union __BDT +{ + struct + { + BD_STAT STAT; + uint8_t CNT; + uint8_t ADRL; //Buffer Address Low + uint8_t ADRH; //Buffer Address High + }; + struct + { + unsigned :8; + unsigned :8; + uint16_t ADR; //Buffer Address + }; + uint32_t Val; + uint8_t v[4]; +} BDT_ENTRY; + +// USTAT Register Layout +typedef union __USTAT +{ + struct + { + unsigned char filler1:1; + unsigned char ping_pong:1; + unsigned char direction:1; + unsigned char endpoint_number:4; + }; + uint8_t Val; +} USTAT_FIELDS; + +//Macros for fetching parameters from a USTAT_FIELDS variable. +#define USBHALGetLastEndpoint(stat) stat.endpoint_number +#define USBHALGetLastDirection(stat) stat.direction +#define USBHALGetLastPingPong(stat) stat.ping_pong + + +typedef union _POINTER +{ + struct + { + uint8_t bLow; + uint8_t bHigh; + //byte bUpper; + }; + uint16_t _word; // bLow & bHigh + + //pFunc _pFunc; // Usage: ptr.pFunc(); Init: ptr.pFunc = &; + + uint8_t* bRam; // Ram byte pointer: 2 bytes pointer pointing + // to 1 byte of data + uint16_t* wRam; // Ram word poitner: 2 bytes poitner pointing + // to 2 bytes of data + + const uint8_t* bRom; // Size depends on compiler setting + const uint16_t* wRom; + //rom near byte* nbRom; // Near = 2 bytes pointer + //rom near word* nwRom; + //rom far byte* fbRom; // Far = 3 bytes pointer + //rom far word* fwRom; +} POINTER; + +// ***************************************************************************** +// ***************************************************************************** +// Section: Interface Routines +// ***************************************************************************** +// ***************************************************************************** + +#define ConvertToPhysicalAddress(a) ((uint16_t)(a)) +#define ConvertToVirtualAddress(a) ((void *)(a)) + + +//------------------------------------------------------------------------------ +//This section is for the PIC18F45K50 Family microcontrollers +//------------------------------------------------------------------------------ +#if defined(__18F45K50) || defined(__18F25K50) || defined(__18F24K50) || defined(__18LF45K50) || defined(__18LF25K50) || defined(__18LF24K50) + #define USBClearUSBInterrupt() PIR3bits.USBIF = 0; + #if defined(USB_INTERRUPT) + #define USBMaskInterrupts() {PIE3bits.USBIE = 0;} + #define USBUnmaskInterrupts() {PIE3bits.USBIE = 1;} + #else + #define USBMaskInterrupts() + #define USBUnmaskInterrupts() + #endif + + #define USBInterruptFlag PIR3bits.USBIF + + //STALLIE, IDLEIE, TRNIE, and URSTIE are all enabled by default and are required + #if defined(USB_INTERRUPT) + #define USBEnableInterrupts() {RCONbits.IPEN = 1;IPR3bits.USBIP = 1;PIE3bits.USBIE = 1;INTCONbits.GIEH = 1;} + #else + #define USBEnableInterrupts() + #endif + + #define USBDisableInterrupts() {PIE3bits.USBIE = 0;} + + #define SetConfigurationOptions() {\ + U1CNFG1 = USB_PULLUP_OPTION | USB_TRANSCEIVER_OPTION | USB_SPEED_OPTION | USB_PING_PONG_MODE;\ + U1EIE = 0x9F;\ + UIE = 0x39 | USB_SOF_INTERRUPT | USB_ERROR_INTERRUPT;\ + } + +//------------------------------------------------------------------------------ +//This section is for the PIC16F145x Family Microcontrollers +//------------------------------------------------------------------------------ +#elif defined(__16F1454) || defined(__16F1455) || defined(__16F1459) || defined(__16LF1454) || defined(__16LF1455) || defined(__16LF1459) + #define USBClearUSBInterrupt() PIR2bits.USBIF = 0; + #if defined(USB_INTERRUPT) + #define USBMaskInterrupts() {PIE2bits.USBIE = 0;} + #define USBUnmaskInterrupts() {PIE2bits.USBIE = 1;} + #else + #define USBMaskInterrupts() + #define USBUnmaskInterrupts() + #endif + + #define USBInterruptFlag PIR2bits.USBIF + + //STALLIE, IDLEIE, TRNIE, and URSTIE are all enabled by default and are required + #if defined(USB_INTERRUPT) + #define USBEnableInterrupts() {PIE2bits.USBIE = 1;INTCONbits.PEIE = 1;INTCONbits.GIE = 1;} + #else + #define USBEnableInterrupts() + #endif + + #define USBDisableInterrupts() {PIE2bits.USBIE = 0;} + + #define SetConfigurationOptions() {\ + U1CNFG1 = USB_PULLUP_OPTION | USB_TRANSCEIVER_OPTION | USB_SPEED_OPTION | USB_PING_PONG_MODE;\ + U1EIE = 0x9F;\ + UIE = 0x39 | USB_SOF_INTERRUPT | USB_ERROR_INTERRUPT;\ + } +#else +//------------------------------------------------------------------------------ +//This section is for all other PIC18 USB microcontrollers +//------------------------------------------------------------------------------ + #define USBClearUSBInterrupt() {PIR2bits.USBIF = 0;} + #if defined(USB_INTERRUPT) + #define USBMaskInterrupts() {PIE2bits.USBIE = 0;} + #define USBUnmaskInterrupts() {PIE2bits.USBIE = 1;} + #else + #define USBMaskInterrupts() + #define USBUnmaskInterrupts() + #endif + + #define USBInterruptFlag PIR2bits.USBIF + + //STALLIE, IDLEIE, TRNIE, and URSTIE are all enabled by default and are required + #if defined(USB_INTERRUPT) + #define USBEnableInterrupts() {RCONbits.IPEN = 1;IPR2bits.USBIP = 1;PIE2bits.USBIE = 1;INTCONbits.GIEH = 1;} + #else + #define USBEnableInterrupts() + #endif + + #define USBDisableInterrupts() {PIE2bits.USBIE = 0;} + + #define SetConfigurationOptions() {\ + U1CNFG1 = USB_PULLUP_OPTION | USB_TRANSCEIVER_OPTION | USB_SPEED_OPTION | USB_PING_PONG_MODE;\ + U1EIE = 0x9F;\ + UIE = 0x39 | USB_SOF_INTERRUPT | USB_ERROR_INTERRUPT;\ + } +#endif //end of #if defined(__18F45K50) || defined(__18F25K50)... +//------------------------------------------------------------------------------ + + +/**************************************************************** + Function: + void USBPowerModule(void) + + Description: + This macro is used to power up the USB module if required
+ PIC18: defines as nothing
+ PIC24: defines as U1PWRCbits.USBPWR = 1;
+ + Parameters: + None + + Return Values: + None + + Remarks: + None + + ****************************************************************/ +#define USBPowerModule() + +/**************************************************************** + Function: + void USBModuleDisable(void) + + Description: + This macro is used to disable the USB module + + Parameters: + None + + Return Values: + None + + Remarks: + None + + ****************************************************************/ +#define USBModuleDisable() {\ + UCON = 0;\ + UIE = 0;\ + USBDeviceState = DETACHED_STATE;\ +} + +/**************************************************************** + Function: + USBSetBDTAddress(addr) + + Description: + This macro is used to power up the USB module if required + + Parameters: + None + + Return Values: + None + + Remarks: + None + + ****************************************************************/ +#define USBSetBDTAddress(addr) + +/******************************************************************** + * Function (macro): void USBClearInterruptFlag(register, uint8_t if_and_flag_mask) + * + * PreCondition: None + * + * Input: + * register - the register mnemonic for the register holding the interrupt + flag to be cleared + * uint8_t if_and_flag_mask - an AND mask for the interrupt flag that will be + cleared + * + * Output: None + * + * Side Effects: None + * + * Overview: Clears the specified USB interrupt flag. + * + * Note: + *******************************************************************/ +#define USBClearInterruptFlag(reg_name, if_and_flag_mask) (reg_name &= if_and_flag_mask) + +/******************************************************************** + Function: + void USBClearInterruptRegister(uint16_t reg) + + Summary: + Clears the specified interrupt register + + PreCondition: + None + + Parameters: + uint16_t reg - the register name that needs to be cleared + + Return Values: + None + + Remarks: + None + + *******************************************************************/ +#define USBClearInterruptRegister(reg) {reg = 0;} + +/******************************************************************** + Function: + void DisableNonZeroEndpoints(UINT8 last_ep_num) + + Summary: + Clears the control registers for the specified non-zero endpoints + + PreCondition: + None + + Parameters: + UINT8 last_ep_num - the last endpoint number to clear. This + number should include all endpoints used in any configuration. + + Return Values: + None + + Remarks: + None + + *******************************************************************/ +#define DisableNonZeroEndpoints(last_ep_num) memset((void*)&U1EP1,0x00,(last_ep_num)); + +/*****************************************************************************/ +/****** Compiler checks ******************************************************/ +/*****************************************************************************/ + +//Definitions for the BDT +#ifndef USB_PING_PONG_MODE + #error "No ping pong mode defined." +#endif + +/*****************************************************************************/ +/****** Extern variable definitions ******************************************/ +/*****************************************************************************/ + +#if !defined(USBDEVICE_C) + extern USB_VOLATILE uint8_t USBActiveConfiguration; + extern USB_VOLATILE IN_PIPE inPipes[1]; + extern USB_VOLATILE OUT_PIPE outPipes[1]; +#endif + +extern volatile BDT_ENTRY* pBDTEntryOut[USB_MAX_EP_NUMBER+1]; +extern volatile BDT_ENTRY* pBDTEntryIn[USB_MAX_EP_NUMBER+1]; + +#ifdef __cplusplus // Provide C++ Compatibility + } +#endif + +#endif //#ifndef _USB_HAL_PIC18_H + + diff --git a/l.obj b/l.obj new file mode 100644 index 0000000..090a66e Binary files /dev/null and b/l.obj differ diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml new file mode 100644 index 0000000..a6ab6ff --- /dev/null +++ b/nbproject/configurations.xml @@ -0,0 +1,583 @@ + + + + + + inc/drivers/app_led_usb_status.h + inc/drivers/eeprom.h + inc/drivers/joystick.h + inc/drivers/adc.h + inc/drivers/buttons.h + inc/drivers/leds.h + + + inc/usb/usb.h + inc/usb/usb_ch9.h + inc/usb/usb_common.h + inc/usb/usb_config.h + inc/usb/usb_device.h + inc/usb/usb_device_hid.h + inc/usb/usb_device_local.h + inc/usb/usb_hal.h + inc/usb/usb_hal_pic18.h + + inc/fixed_address_memory.h + inc/io_mapping.h + inc/system.h + + + + + + src/drivers/app_led_usb_status.c + src/drivers/eeprom.c + src/drivers/joystick.c + src/drivers/adc.c + src/drivers/buttons.c + src/drivers/leds.c + + + src/usb/usb_descriptors.c + src/usb/usb_events.c + src/usb/usb_device.c + src/usb/usb_device_hid.c + + src/main.c + src/system.c + + + Makefile + + + + . + src/drivers + src/usb + + Makefile + + + + localhost + PIC18F14K50 + + + PICkit2PlatformTool + XC8 + 1.42 + 4 + + + + + + + + + + false + true + + + + + + + false + + false + + false + false + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nbproject/project.xml b/nbproject/project.xml new file mode 100644 index 0000000..1ada48c --- /dev/null +++ b/nbproject/project.xml @@ -0,0 +1,16 @@ + + + com.microchip.mplab.nbide.embedded.makeproject + + + Apple_II_USB + 0 + c + + h + UTF-8 + + + + + diff --git a/src/drivers/adc.c b/src/drivers/adc.c new file mode 100644 index 0000000..fe62373 --- /dev/null +++ b/src/drivers/adc.c @@ -0,0 +1,207 @@ +/******************************************************************** + Software License Agreement: + + The software supplied herewith by Microchip Technology Incorporated + (the "Company") for its PIC(R) Microcontroller is intended and + supplied to you, the Company's customer, for use solely and + exclusively on Microchip PIC Microcontroller products. The + software is owned by the Company and/or its supplier, and is + protected under applicable copyright laws. All rights are reserved. + Any use in violation of the foregoing restrictions may subject the + user to criminal sanctions under applicable laws, as well as to + civil liability for the breach of the terms and conditions of this + license. + + THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, + WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED + TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, + IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR + CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + *******************************************************************/ + +#include +#include +#include +#include + +#include + +#define PIN_ANALOG 1 +#define PIN_DIGITAL 0 + +#define PIN_INPUT 1 +#define PIN_OUTPUT 0 + +/********************************************************************* +* Function: ADC_ReadPercentage(ADC_CHANNEL channel); +* +* Overview: Reads the requested ADC channel and returns the percentage +* of that conversions result (0-100%). +* +* PreCondition: channel is configured via the ADCConfigure() function +* +* Input: ADC_CHANNEL channel - enumeration of the ADC channels +* available in this demo. They should be meaningful names and +* not the names of the ADC pins on the device (as the demo code +* may be ported to other boards). +* i.e. ADC_ReadPercentage(ADC_CHANNEL_POTENTIOMETER); +* +* Output: uint8_t indicating the percentage of the result 0-100% or +* 0xFF for an error +* +********************************************************************/ +uint8_t ADC_ReadPercentage + (ADC_CHANNEL channel) { + uint8_t percent; + + switch(channel) + { + case ADC_CHANNEL_8: + break; + case ADC_CHANNEL_9: + break; + default: + return 0xFF; + } + + //A very crude percentage calculation + percent = (ADC_Read10bit(channel) / 10); + + if(percent > 100) + { + percent = 100; + } + return percent; +} + +/********************************************************************* +* Function: ADC_Read10bit(ADC_CHANNEL channel); +* +* Overview: Reads the requested ADC channel and returns the 10-bit +* representation of this data. +* +* PreCondition: channel is configured via the ADCConfigure() function +* +* Input: ADC_CHANNEL channel - enumeration of the ADC channels +* available in this demo. They should be meaningful names and +* not the names of the ADC pins on the device (as the demo code +* may be ported to other boards). +* i.e. - ADCReadPercentage(ADC_CHANNEL_POTENTIOMETER); +* +* Output: uint16_t the right adjusted 10-bit representation of the ADC +* channel conversion or 0xFFFF for an error. +* +********************************************************************/ +uint16_t ADC_Read10bit(ADC_CHANNEL channel) +{ + uint16_t result; + + switch(channel) + { + case ADC_CHANNEL_8: + break; + case ADC_CHANNEL_9: + break; + default: + return 0xFFFF; + } + + ADCON0bits.CHS = channel; + + ADCON0bits.GO = 1; // Start AD conversion + while(ADCON0bits.NOT_DONE); // Wait for conversion + + result = ADRESH; + result <<=8; + result |= ADRESL; + + return result; +} + +uint8_t ADC_Read8bit(ADC_CHANNEL channel) +{ + uint8_t result; + + switch(channel) + { + case ADC_CHANNEL_8: + break; + case ADC_CHANNEL_9: + break; + default: + return 0xFFFF; + } + + ADCON0bits.CHS = channel; + + ADCON0bits.GO = 1; // Start AD conversion + while(ADCON0bits.NOT_DONE); // Wait for conversion + + result = ADRESH; + //result <<=8; + //result |= ADRESL; + + return result; +} + +/********************************************************************* +* Function: bool ADC_Enable(ADC_CHANNEL channel, ADC_CONFIGURATION configuration); +* +* Overview: Configures the ADC module to specified setting +* +* PreCondition: none +* +* Input: ADC_CHANNEL channel - the channel to enable +* ADC_CONFIGURATION configuration - the mode in which to run the ADC +* +* Output: bool - true if successfully configured. false otherwise. +* +********************************************************************/ +bool ADC_Enable(ADC_CHANNEL channel) +{ + switch(channel) + { + case ADC_CHANNEL_8: + TRISCbits.TRISC6 = PIN_INPUT; + ANSELHbits.ANS8 = PIN_ANALOG; + return true; + case ADC_CHANNEL_9: + TRISCbits.TRISC7 = PIN_INPUT; + ANSELHbits.ANS9 = PIN_ANALOG; + return true; + default: + return false; + } +} + +/********************************************************************* +* Function: bool ADC_SetConfiguration(ADC_CONFIGURATION configuration) +* +* Overview: Configures the ADC module to specified setting +* +* PreCondition: none +* +* Input: ADC_CONFIGURATION configuration - the mode in which to run the ADC +* +* Output: bool - true if successfully configured. false otherwise. +* +********************************************************************/ +bool ADC_SetConfiguration(ADC_CONFIGURATION configuration) +{ + if(configuration == ADC_CONFIGURATION_DEFAULT) + { + //ADCON0=0b00000001; + ADCON0bits.ADON = 1; + + ADCON1=0b00000000; + //ADCON2=0b00111110; + ADCON2bits.ACQT = 0b111; + ADCON2bits.ADCS = 0b110; + ADCON2bits.ADFM = 1; + + return true; + } + + return false; +} diff --git a/src/drivers/app_led_usb_status.c b/src/drivers/app_led_usb_status.c new file mode 100644 index 0000000..2bac58f --- /dev/null +++ b/src/drivers/app_led_usb_status.c @@ -0,0 +1,34 @@ +#include "stdint.h" +#include "system.h" +#include "usb_device.h" + +void APP_LEDUpdateUSBStatus(void) { + static uint16_t ledCount = 0; + + // If device is suspended, LED is turned off + if (USBIsDeviceSuspended() == true) { + LED_Off(LED_USB_DEVICE_STATE); + return; + } + + switch (USBGetDeviceState()) { + // If device is configured, LED on + case CONFIGURED_STATE: + LED_On(LED_USB_DEVICE_STATE); + break; + + default: + // Not configured so slow blink + if (ledCount == 1) { + LED_On(LED_USB_DEVICE_STATE); + } else if (ledCount == 50) { + LED_Off(LED_USB_DEVICE_STATE); + } else if (ledCount > 950) { + ledCount = 0; + } + break; + } + + /* Increment the millisecond counter. */ + ledCount++; +} \ No newline at end of file diff --git a/src/drivers/buttons.c b/src/drivers/buttons.c new file mode 100644 index 0000000..20177ef --- /dev/null +++ b/src/drivers/buttons.c @@ -0,0 +1,105 @@ +/******************************************************************** + Software License Agreement: + + The software supplied herewith by Microchip Technology Incorporated + (the "Company") for its PIC(R) Microcontroller is intended and + supplied to you, the Company's customer, for use solely and + exclusively on Microchip PIC Microcontroller products. The + software is owned by the Company and/or its supplier, and is + protected under applicable copyright laws. All rights are reserved. + Any use in violation of the foregoing restrictions may subject the + user to criminal sanctions under applicable laws, as well as to + civil liability for the breach of the terms and conditions of this + license. + + THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, + WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED + TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, + IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR + CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + *******************************************************************/ + +#include +#include +#include + +/*** Button Definitions *********************************************/ +#define S1_PORT PORTCbits.RC0 +#define S2_PORT PORTCbits.RC1 + +#define S1_TRIS TRISCbits.TRISC0 +#define S2_TRIS TRISCbits.TRISC1 + +#define BUTTON_PRESSED 1 +#define BUTTON_NOT_PRESSED 0 + +#define PIN_INPUT 1 +#define PIN_OUTPUT 0 + +#define PIN_DIGITAL 0 +#define PIN_ANALOG 1 + +/********************************************************************* + * Function: bool BUTTON_IsPressed(BUTTON button); + * + * Overview: Returns the current state of the requested button + * + * PreCondition: button configured via BUTTON_SetConfiguration() + * + * Input: BUTTON button - enumeration of the buttons available in + * this demo. They should be meaningful names and not the names + * of the buttons on the silkscreen on the board (as the demo + * code may be ported to other boards). + * i.e. - ButtonIsPressed(BUTTON_SEND_MESSAGE); + * + * Output: TRUE if pressed; FALSE if not pressed. + * + ********************************************************************/ +bool BUTTON_IsPressed(BUTTON button) { + switch (button) { + case BUTTON_S1: + return ( (S1_PORT == BUTTON_PRESSED) ? true : false); + + case BUTTON_S2: + return ( (S2_PORT == BUTTON_PRESSED) ? true : false); + + case BUTTON_NONE: + return false; + } + + return false; +} + +/********************************************************************* + * Function: void BUTTON_Enable(BUTTON button); + * + * Overview: Returns the current state of the requested button + * + * PreCondition: button configured via BUTTON_SetConfiguration() + * + * Input: BUTTON button - enumeration of the buttons available in + * this demo. They should be meaningful names and not the names + * of the buttons on the silkscreen on the board (as the demo + * code may be ported to other boards). + * i.e. - ButtonIsPressed(BUTTON_SEND_MESSAGE); + * + * Output: None + * + ********************************************************************/ +void BUTTON_Enable(BUTTON button) { + switch (button) { + case BUTTON_S1: + S1_TRIS = PIN_INPUT; + ANSELbits.ANS4 = PIN_DIGITAL; + break; + + case BUTTON_S2: + S2_TRIS = PIN_INPUT; + ANSELbits.ANS5 = PIN_DIGITAL; + break; + + case BUTTON_NONE: + break; + } +} diff --git a/src/drivers/eeprom.c b/src/drivers/eeprom.c new file mode 100644 index 0000000..6852791 --- /dev/null +++ b/src/drivers/eeprom.c @@ -0,0 +1,51 @@ +/* + * EEPROM routines + * www.flitey.com + */ + +#include +#include +#include + +unsigned char EepromReadByte(uint8_t byteAddress) { + EEADR = byteAddress; + EECON1bits.CFGS = 0; + EECON1bits.EEPGD = 0; + EECON1bits.RD = 1; + Nop(); //Nop may be required for latency at high frequencies + Nop(); //Nop may be required for latency at high frequencies + return (EEDATA); +} + +void EepromWriteByte(uint8_t byteAddress, uint8_t byteData) { + bool GIE_BIT_VAL; + + EEADR = byteAddress; + EEDATA = byteData; + EECON1bits.EEPGD = 0; + EECON1bits.CFGS = 0; + EECON1bits.WREN = 1; + GIE_BIT_VAL = INTCONbits.GIE; + INTCONbits.GIE = 0; + EECON2 = 0x55; // critical unlock sequence + EECON2 = 0xAA; + EECON1bits.WR = 1; // end critical sequence + while (EECON1bits.WR); //Wait till the write completion + INTCONbits.GIE = GIE_BIT_VAL; + EECON1bits.WREN = 0; +} + +uint16_t EepromReadTwoBytes(uint8_t startAddress) { + unsigned char highByte = EepromReadByte(startAddress); + unsigned char lowByte = EepromReadByte(startAddress + 1); + uint16_t result = (highByte << 8) | lowByte; + return result; +} + +void EepromWriteTwoBytes(uint8_t startAddress, uint16_t value) { + uint8_t high = (value & 0xFF00) >> 8; + uint8_t low = (value & 0x00FF); + + EepromWriteByte(startAddress, high); + EepromWriteByte(startAddress + 1, low); +} \ No newline at end of file diff --git a/src/drivers/joystick.c b/src/drivers/joystick.c new file mode 100644 index 0000000..494465e --- /dev/null +++ b/src/drivers/joystick.c @@ -0,0 +1,271 @@ +/** + * Joystick functions + * www.flitey.com + */ + +#ifndef USBJOYSTICK_C +#define USBJOYSTICK_C + +/** INCLUDES *******************************************************/ +#include "usb.h" +#include "usb_device_hid.h" +#include "system.h" +#include "app_led_usb_status.h" +#include "stdint.h" +#include "system.h" +#include "eeprom.h" + +/** DECLARATIONS ***************************************************/ +uint8_t joystick_counter = 0; +bool calibrated = false; +uint16_t x_axis_center = JOYSTICK_10_BIT_MID; +uint16_t y_axis_center = JOYSTICK_10_BIT_MID; +uint16_t x_axis_max = JOYSTICK_10_BIT_MID; +uint16_t x_axis_min = JOYSTICK_10_BIT_MID; +uint16_t y_axis_max = JOYSTICK_10_BIT_MID; +uint16_t y_axis_min = JOYSTICK_10_BIT_MID; + +/** TYPE DEFINITIONS ************************************************/ +typedef union _INTPUT_CONTROLS_TYPEDEF { + + struct { + + struct { + uint8_t x : 1; + uint8_t y : 1; +uint8_t: + 6; //filler + } buttons; + + struct { + uint8_t X; + uint8_t Y; + } analog_stick; + } members; + uint8_t val[3]; +} INPUT_CONTROLS; + +INPUT_CONTROLS joystick_input @ JOYSTICK_DATA_ADDRESS; + +USB_VOLATILE USB_HANDLE lastTransmission = 0; + +void JoystickInitialize(void) { + lastTransmission = 0; + + //enable the HID endpoint + USBEnableEndpoint(JOYSTICK_EP, USB_IN_ENABLED | USB_HANDSHAKE_ENABLED | USB_DISALLOW_SETUP); +} + +/** + * Calibrate the joystick potentiometers. We wait for the button to be released + * and then start the calibration. Calibration looks for the min and max values + * for each potentiometer and also checks if one of the buttons has been pressed. + * The button press indicates calibration is complete. + */ +void JoystickRunCalibration() { + + while (BUTTON_IsPressed(GAME_SWITCH_0) == true || BUTTON_IsPressed(GAME_SWITCH_1) == true) { + // wait for buttons to be released + } + + uint16_t ledCounter = 0; + while (!calibrated) { + + if (ledCounter == 1) { + LED_On(LED_USB_DEVICE_STATE); + } else if (ledCounter == 5000) { + LED_Off(LED_USB_DEVICE_STATE); + } else if (ledCounter == 10000) { + ledCounter = 0; + } + + uint16_t X_axis = ADC_Read10bit(PDL0); + uint16_t Y_axis = ADC_Read10bit(PDL1); + + if (X_axis >= x_axis_max) { + x_axis_max = X_axis; + } + if (X_axis <= x_axis_min) { + x_axis_min = X_axis; + } + if (Y_axis >= y_axis_max) { + y_axis_max = Y_axis; + } + if (Y_axis <= y_axis_min) { + y_axis_min = Y_axis; + } + + if (BUTTON_IsPressed(GAME_SWITCH_0) == true || BUTTON_IsPressed(GAME_SWITCH_1) == true) { + + while (BUTTON_IsPressed(GAME_SWITCH_0) == true || BUTTON_IsPressed(GAME_SWITCH_1) == true) { + // wait + } + + LED_Off(LED_USB_DEVICE_STATE); + + // Very arbitrary wait time so we can make sure the center value is stable + uint16_t waitCount = 0; + for (uint8_t i = 0; i < 40; i++) { + while (waitCount < 65000) { + waitCount++; + } + } + + X_axis = ADC_Read10bit(PDL0); + Y_axis = ADC_Read10bit(PDL1); + + x_axis_center = X_axis; + y_axis_center = Y_axis; + + EepromWriteTwoBytes(X_AXIS_MIN_EEPROM_ADDRESS, x_axis_min); + EepromWriteTwoBytes(X_AXIS_MID_EEPROM_ADDRESS, x_axis_center); + EepromWriteTwoBytes(X_AXIS_MAX_EEPROM_ADDRESS, x_axis_max); + + EepromWriteTwoBytes(Y_AXIS_MIN_EEPROM_ADDRESS, y_axis_min); + EepromWriteTwoBytes(Y_AXIS_MID_EEPROM_ADDRESS, y_axis_center); + EepromWriteTwoBytes(Y_AXIS_MAX_EEPROM_ADDRESS, y_axis_max); + + calibrated = true; + } + + ledCounter++; + } +} + +/** + * Verifies the specified value is within the valid range + * @param value the value to test + * @return true if value is within the range, otherwise false + */ +bool isValidCalibrationValue(uint16_t value) { + if (value <= JOYSTICK_10_BIT_MAX && value >= JOYSTICK_10_BIT_MIN) { + return true; + } else { + return false; + } +} + +void JoystickUseSavedCalibration(uint16_t x_min, uint16_t x_mid, uint16_t x_max, uint16_t y_min, uint16_t y_mid, uint16_t y_max) { + + if (isValidCalibrationValue(x_min)) { + x_axis_min = x_min; + } else { + x_axis_min = JOYSTICK_10_BIT_MIN; + } + + if (isValidCalibrationValue(x_mid)) { + x_axis_center = x_mid; + } else { + x_axis_center = JOYSTICK_10_BIT_MID; + } + + if (isValidCalibrationValue(x_max)) { + x_axis_max = x_max; + } else { + x_axis_max = JOYSTICK_10_BIT_MAX; + } + + if (isValidCalibrationValue(y_min)) { + y_axis_min = y_min; + } else { + y_axis_min = JOYSTICK_10_BIT_MIN; + } + + if (isValidCalibrationValue(y_mid)) { + y_axis_center = y_mid; + } else { + y_axis_center = JOYSTICK_10_BIT_MID; + } + + if (isValidCalibrationValue(y_max)) { + y_axis_max = y_max; + } else { + y_axis_max = JOYSTICK_10_BIT_MAX; + } + + calibrated = true; +} + +/** + * Converts the ADC value to be within the calibration range. + * @param ADCValue the 10 bit value read from the ADC + * @param inputMin the min calibration value for this axis + * @param inputMid the midpoint calibration value for this axis + * @param inputMax the max calibration value for this axis + * @return the final joystick value mapped to the calibration range + */ +uint8_t convertValue(uint16_t ADCValue, uint16_t inputMin, uint16_t inputMid, uint16_t inputMax) { + + // Prevent output from going beyond the min and max values + if (ADCValue > inputMax) { + ADCValue = inputMax; + } else if (ADCValue < inputMin) { + ADCValue = inputMin; + } + + uint16_t input_end = inputMax; + uint16_t input_start = inputMid; + uint16_t output_end = JOYSTICK_8_BIT_MAX_OUTPUT; + uint16_t output_start = JOYSTICK_8_BIT_MID_OUTPUT; + if (ADCValue < inputMid) { + input_end = inputMid - 1; + input_start = inputMin; + output_end = JOYSTICK_8_BIT_MID_OUTPUT - 1; + output_start = JOYSTICK_8_BIT_MIN_OUTPUT; + } + double x_slope = 1.0 * (output_end - output_start) / (input_end - input_start); + uint16_t sixteenBitOutput = output_start + x_slope * (ADCValue - input_start); + + uint8_t finalOutput = JOYSTICK_8_BIT_MAX_OUTPUT - (uint8_t) sixteenBitOutput; + + return finalOutput; +} + +void JoystickTasks(void) { + + if (USBGetDeviceState() < CONFIGURED_STATE) { + return; + } + + if (USBIsDeviceSuspended() == true) { + return; + } + + //If the last transmission is complete + if (!HIDTxHandleBusy(lastTransmission)) { + + if (joystick_counter > 5) { + + if (BUTTON_IsPressed(GAME_SWITCH_0) == true) { + joystick_input.members.buttons.x = 1; + } else { + joystick_input.members.buttons.x = 0; + } + + if (BUTTON_IsPressed(GAME_SWITCH_1) == true) { + joystick_input.members.buttons.y = 1; + } else { + joystick_input.members.buttons.y = 0; + } + + uint16_t X_axis = ADC_Read10bit(PDL0); + uint16_t Y_axis = ADC_Read10bit(PDL1); + + uint8_t x_output = convertValue(X_axis, x_axis_min, x_axis_center, x_axis_max); + uint8_t y_output = convertValue(Y_axis, y_axis_min, y_axis_center, y_axis_max); + + joystick_input.members.analog_stick.X = x_output; + joystick_input.members.analog_stick.Y = y_output; + + joystick_counter = 0; + } else { + joystick_counter++; + } + + //Send the packet over USB to the host. + lastTransmission = HIDTxPacket(JOYSTICK_EP, (uint8_t*) & joystick_input, sizeof (joystick_input)); + } + +} + +#endif diff --git a/src/drivers/leds.c b/src/drivers/leds.c new file mode 100644 index 0000000..b79e9c2 --- /dev/null +++ b/src/drivers/leds.c @@ -0,0 +1,180 @@ +/******************************************************************** + Software License Agreement: + + The software supplied herewith by Microchip Technology Incorporated + (the "Company") for its PIC(R) Microcontroller is intended and + supplied to you, the Company's customer, for use solely and + exclusively on Microchip PIC Microcontroller products. The + software is owned by the Company and/or its supplier, and is + protected under applicable copyright laws. All rights are reserved. + Any use in violation of the foregoing restrictions may subject the + user to criminal sanctions under applicable laws, as well as to + civil liability for the breach of the terms and conditions of this + license. + + THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, + WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED + TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, + IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR + CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + *******************************************************************/ + +#include +#include +#include + +#define LED_D1_LAT LATBbits.LATB4 + +#define LED_D1_TRIS TRISBbits.TRISB4 + +#define LED_ON 1 +#define LED_OFF 0 + +#define PIN_INPUT 1 +#define PIN_OUTPUT 0 + +/********************************************************************* +* Function: void LED_On(LED led); +* +* Overview: Turns requested LED on +* +* PreCondition: LED configured via LED_Configure() +* +* Input: LED led - enumeration of the LEDs available in this +* demo. They should be meaningful names and not the names of +* the LEDs on the silkscreen on the board (as the demo code may +* be ported to other boards). +* i.e. - LED_On(LED_CONNECTION_DETECTED); +* +* Output: none +* +********************************************************************/ +void LED_On(LED led) +{ + switch(led) + { + case LED_D1: + LED_D1_LAT = LED_ON; + break; + + case LED_NONE: + break; + } +} + +/********************************************************************* +* Function: void LED_Off(LED led); +* +* Overview: Turns requested LED off +* +* PreCondition: LED configured via LEDConfigure() +* +* Input: LED led - enumeration of the LEDs available in this +* demo. They should be meaningful names and not the names of +* the LEDs on the silkscreen on the board (as the demo code may +* be ported to other boards). +* i.e. - LED_Off(LED_CONNECTION_DETECTED); +* +* Output: none +* +********************************************************************/ +void LED_Off(LED led) +{ + switch(led) + { + case LED_D1: + LED_D1_LAT = LED_OFF; + break; + + case LED_NONE: + break; + } +} + +/********************************************************************* +* Function: void LED_Toggle(LED led); +* +* Overview: Toggles the state of the requested LED +* +* PreCondition: LED configured via LEDConfigure() +* +* Input: LED led - enumeration of the LEDs available in this +* demo. They should be meaningful names and not the names of +* the LEDs on the silkscreen on the board (as the demo code may +* be ported to other boards). +* i.e. - LED_Toggle(LED_CONNECTION_DETECTED); +* +* Output: none +* +********************************************************************/ +void LED_Toggle(LED led) +{ + switch(led) + { + case LED_D1: + LED_D1_LAT ^= 1; + break; + + case LED_NONE: + break; + } +} + +/********************************************************************* +* Function: bool LED_Get(LED led); +* +* Overview: Returns the current state of the requested LED +* +* PreCondition: LED configured via LEDConfigure() +* +* Input: LED led - enumeration of the LEDs available in this +* demo. They should be meaningful names and not the names of +* the LEDs on the silkscreen on the board (as the demo code may +* be ported to other boards). +* i.e. - LED_Get(LED_CONNECTION_DETECTED); +* +* Output: true if on, false if off +* +********************************************************************/ +bool LED_Get(LED led) +{ + switch(led) + { + case LED_D1: + return ( (LED_D1_LAT == LED_ON) ? true : false ); + + case LED_NONE: + return false; + } + + return false; +} + +/********************************************************************* +* Function: void LED_Enable(LED led); +* +* Overview: Configures the LED for use by the other LED API +* +* PreCondition: none +* +* Input: LED led - enumeration of the LEDs available in this +* demo. They should be meaningful names and not the names of +* the LEDs on the silkscreen on the board (as the demo code may +* be ported to other boards). +* +* Output: none +* +********************************************************************/ +void LED_Enable(LED led) +{ + switch(led) + { + case LED_D1: + LED_D1_TRIS = PIN_OUTPUT; + break; + + case LED_NONE: + break; + } +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..e2c9533 --- /dev/null +++ b/src/main.c @@ -0,0 +1,100 @@ +/** + * Apple II Joystick to USB Adapter + * www.flitey.com + */ + +/** INCLUDES *******************************************************/ +#include "system.h" + +#include "usb.h" +#include "usb_device_hid.h" + +#include "joystick.h" +#include "app_led_usb_status.h" + +#include "eeprom.h" + +// Define default EEPROM data for min/max calibration values +// [ X MIN ] [ X MID ] [ X MAX ] [ Y MIN ] +__EEPROM_DATA(0x00, 0x00, 0x01, 0xFF, 0x03, 0xFF, 0x00, 0x00); + +// [ Y MID ] [ Y MAX ] +__EEPROM_DATA(0x01, 0xFF, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00); + +/** + * Main function + */ +void main(void) { + + // Initialize the buttons, LEDs, ADC + SYSTEM_Initialize(SYSTEM_STATE_USB_START); + + // Check button states + bool isSwitch0Pressed = BUTTON_IsPressed(GAME_SWITCH_0); + bool isSwitch1Pressed = BUTTON_IsPressed(GAME_SWITCH_1); + + // If both switches are pressed, we will reset the calibration to the + // standard values. + if (isSwitch0Pressed == true && isSwitch1Pressed == true) { + + // First set the values to be used + JoystickUseSavedCalibration(JOYSTICK_10_BIT_MIN, JOYSTICK_10_BIT_MID, + JOYSTICK_10_BIT_MAX, JOYSTICK_10_BIT_MIN, JOYSTICK_10_BIT_MID, + JOYSTICK_10_BIT_MAX); + + // And then save them to the EEPROM + EepromWriteTwoBytes(X_AXIS_MIN_EEPROM_ADDRESS, JOYSTICK_10_BIT_MIN); + EepromWriteTwoBytes(X_AXIS_MID_EEPROM_ADDRESS, JOYSTICK_10_BIT_MID); + EepromWriteTwoBytes(X_AXIS_MAX_EEPROM_ADDRESS, JOYSTICK_10_BIT_MAX); + + EepromWriteTwoBytes(Y_AXIS_MIN_EEPROM_ADDRESS, JOYSTICK_10_BIT_MIN); + EepromWriteTwoBytes(Y_AXIS_MID_EEPROM_ADDRESS, JOYSTICK_10_BIT_MID); + EepromWriteTwoBytes(Y_AXIS_MAX_EEPROM_ADDRESS, JOYSTICK_10_BIT_MAX); + + } else if (isSwitch0Pressed == true || isSwitch1Pressed == true) { + // If only one of the switches is pressed, we will run the calibration + // routine to get the new values and save them to EEPROM + + JoystickRunCalibration(); + + } else { + // Otherwise, we will just retrieve the previous calibration values and + // run with those. + uint16_t x_min = EepromReadTwoBytes(X_AXIS_MIN_EEPROM_ADDRESS); + uint16_t x_mid = EepromReadTwoBytes(X_AXIS_MID_EEPROM_ADDRESS); + uint16_t x_max = EepromReadTwoBytes(X_AXIS_MAX_EEPROM_ADDRESS); + + uint16_t y_min = EepromReadTwoBytes(Y_AXIS_MIN_EEPROM_ADDRESS); + uint16_t y_mid = EepromReadTwoBytes(Y_AXIS_MID_EEPROM_ADDRESS); + uint16_t y_max = EepromReadTwoBytes(Y_AXIS_MAX_EEPROM_ADDRESS); + + JoystickUseSavedCalibration(x_min, x_mid, x_max, y_min, y_mid, y_max); + } + + // Initialize USB + USBDeviceInit(); + + // Attach USB + USBDeviceAttach(); + + // Now just loop forever here + while (1) { + + // We are using USB_POLLING so do USB tasks + USBDeviceTasks(); + + // If we are not configured, break from the loop + if (USBGetDeviceState() < CONFIGURED_STATE) { + continue; + } + + // If we are suspended, break from the loop + if (USBIsDeviceSuspended() == true) { + continue; + } + + // Perform joystick related actions + JoystickTasks(); + } +} + diff --git a/src/system.c b/src/system.c new file mode 100644 index 0000000..6ab856c --- /dev/null +++ b/src/system.c @@ -0,0 +1,54 @@ +#include "system.h" + +/** CONFIGURATION Bits **********************************************/ + +#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 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 + +void SYSTEM_Initialize(SYSTEM_STATE state) { + switch (state) { + case SYSTEM_STATE_USB_START: + LED_Enable(LED_USB_DEVICE_STATE); + + BUTTON_Enable(GAME_SWITCH_0); + BUTTON_Enable(GAME_SWITCH_1); + + ADC_SetConfiguration(ADC_CONFIGURATION_DEFAULT); + ADC_Enable(PDL0); + ADC_Enable(PDL1); + + break; + + case SYSTEM_STATE_USB_SUSPEND: + break; + + case SYSTEM_STATE_USB_RESUME: + break; + } +} + diff --git a/src/usb/usb_descriptors.c b/src/usb/usb_descriptors.c new file mode 100644 index 0000000..348d686 --- /dev/null +++ b/src/usb/usb_descriptors.c @@ -0,0 +1,269 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +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. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ + +/******************************************************************** +-usb_descriptors.c- +------------------------------------------------------------------- +Filling in the descriptor values in the usb_descriptors.c file: +------------------------------------------------------------------- + +[Device Descriptors] +The device descriptor is defined as a USB_DEVICE_DESCRIPTOR type. +This type is defined in usb_ch9.h Each entry into this structure +needs to be the correct length for the data type of the entry. + +[Configuration Descriptors] +The configuration descriptor was changed in v2.x from a structure +to a uint8_t array. Given that the configuration is now a byte array +each byte of multi-byte fields must be listed individually. This +means that for fields like the total size of the configuration where +the field is a 16-bit value "64,0," is the correct entry for a +configuration that is only 64 bytes long and not "64," which is one +too few bytes. + +The configuration attribute must always have the _DEFAULT +definition at the minimum. Additional options can be ORed +to the _DEFAULT attribute. Available options are _SELF and _RWU. +These definitions are defined in the usb_device.h file. The +_SELF tells the USB host that this device is self-powered. The +_RWU tells the USB host that this device supports Remote Wakeup. + +[Endpoint Descriptors] +Like the configuration descriptor, the endpoint descriptors were +changed in v2.x of the stack from a structure to a uint8_t array. As +endpoint descriptors also has a field that are multi-byte entities, +please be sure to specify both bytes of the field. For example, for +the endpoint size an endpoint that is 64 bytes needs to have the size +defined as "64,0," instead of "64," + +Take the following example: + // Endpoint Descriptor // + 0x07, //the size of this descriptor // + USB_DESCRIPTOR_ENDPOINT, //Endpoint Descriptor + _EP02_IN, //EndpointAddress + _INT, //Attributes + 0x08,0x00, //size (note: 2 bytes) + 0x02, //Interval + +The first two parameters are self-explanatory. They specify the +length of this endpoint descriptor (7) and the descriptor type. +The next parameter identifies the endpoint, the definitions are +defined in usb_device.h and has the following naming +convention: +_EP<##>_ +where ## is the endpoint number and dir is the direction of +transfer. The dir has the value of either 'OUT' or 'IN'. +The next parameter identifies the type of the endpoint. Available +options are _BULK, _INT, _ISO, and _CTRL. The _CTRL is not +typically used because the default control transfer endpoint is +not defined in the USB descriptors. When _ISO option is used, +addition options can be ORed to _ISO. Example: +_ISO|_AD|_FE +This describes the endpoint as an isochronous pipe with adaptive +and feedback attributes. See usb_device.h and the USB +specification for details. The next parameter defines the size of +the endpoint. The last parameter in the polling interval. + +------------------------------------------------------------------- +Adding a USB String +------------------------------------------------------------------- +A string descriptor array should have the following format: + +rom struct{byte bLength;byte bDscType;word string[size];}sdxxx={ +sizeof(sdxxx),DSC_STR,}; + +The above structure provides a means for the C compiler to +calculate the length of string descriptor sdxxx, where xxx is the +index number. The first two bytes of the descriptor are descriptor +length and type. The rest are string texts which must be +in the unicode format. The unicode format is achieved by declaring +each character as a word type. The whole text string is declared +as a word array with the number of characters equals to . + has to be manually counted and entered into the array +declaration. Let's study this through an example: +if the string is "USB" , then the string descriptor should be: +(Using index 02) +rom struct{byte bLength;byte bDscType;word string[3];}sd002={ +sizeof(sd002),DSC_STR,'U','S','B'}; + +A USB project may have multiple strings and the firmware supports +the management of multiple strings through a look-up table. +The look-up table is defined as: +rom const unsigned char *rom USB_SD_Ptr[]={&sd000,&sd001,&sd002}; + +The above declaration has 3 strings, sd000, sd001, and sd002. +Strings can be removed or added. sd000 is a specialized string +descriptor. It defines the language code, usually this is +US English (0x0409). The index of the string must match the index +position of the USB_SD_Ptr array, &sd000 must be in position +USB_SD_Ptr[0], &sd001 must be in position USB_SD_Ptr[1] and so on. +The look-up table USB_SD_Ptr is used by the get string handler +function. + +------------------------------------------------------------------- + +The look-up table scheme also applies to the configuration +descriptor. A USB device may have multiple configuration +descriptors, i.e. CFG01, CFG02, etc. To add a configuration +descriptor, user must implement a structure similar to CFG01. +The next step is to add the configuration descriptor name, i.e. +cfg01, cfg02,.., to the look-up table USB_CD_Ptr. USB_CD_Ptr[0] +is a dummy place holder since configuration 0 is the un-configured +state according to the definition in the USB specification. + +********************************************************************/ + +/********************************************************************* + * Descriptor specific type definitions are defined in: + * usb_device.h + * + * Configuration options are defined in: + * usb_config.h + ********************************************************************/ + +/** INCLUDES *******************************************************/ +#include "usb.h" +#include "usb_device_hid.h" + +/** CONSTANTS ******************************************************/ +#if defined(COMPILER_MPLAB_C18) +#pragma romdata +#endif + +/* Device Descriptor */ +const USB_DEVICE_DESCRIPTOR device_dsc= +{ + 0x12, // Size of this descriptor in bytes + USB_DESCRIPTOR_DEVICE, // DEVICE descriptor type + 0x0200, // USB Spec Release Number in BCD format + 0x00, // Class Code + 0x00, // Subclass code + 0x00, // Protocol code + USB_EP0_BUFF_SIZE, // Max packet size for EP0, see usb_config.h + 0x04D8, // Vendor ID, see usb_config.h + 0x005E, // Product ID, see usb_config.h + 0x0001, // Device release number in BCD format + 0x01, // Manufacturer string index + 0x02, // Product string index + 0x00, // Device serial number string index + 0x01 // Number of possible configurations +}; + +/* Configuration 1 Descriptor */ +const uint8_t configDescriptor1[]={ + /* Configuration Descriptor */ + 0x09,//sizeof(USB_CFG_DSC), // Size of this descriptor in bytes + USB_DESCRIPTOR_CONFIGURATION, // CONFIGURATION descriptor type + DESC_CONFIG_WORD(0x0022), // Total length of data for this cfg + 1, // Number of interfaces in this cfg + 1, // Index value of this configuration + 0, // Configuration string index + _DEFAULT | _SELF, // Attributes, see usb_device.h + 50, // Max power consumption (2X mA) + + /* Interface Descriptor */ + 0x09,//sizeof(USB_INTF_DSC), // Size of this descriptor in bytes + USB_DESCRIPTOR_INTERFACE, // INTERFACE descriptor type + 0, // Interface Number + 0, // Alternate Setting Number + 1, // Number of endpoints in this intf + HID_INTF, // Class code + 0, // Subclass code + 0, // Protocol code + 0, // Interface string index + + /* HID Class-Specific Descriptor */ + 0x09,//sizeof(USB_HID_DSC)+3, // Size of this descriptor in bytes RRoj hack + DSC_HID, // HID descriptor type + DESC_CONFIG_WORD(0x0111), // HID Spec Release Number in BCD format (1.11) + 0x00, // Country Code (0x00 for Not supported) + HID_NUM_OF_DSC, // Number of class descriptors, see usbcfg.h + DSC_RPT, // Report descriptor type + DESC_CONFIG_WORD(HID_RPT01_SIZE), //sizeof(hid_rpt01), // Size of the report descriptor + + /* Endpoint Descriptor */ + 0x07,/*sizeof(USB_EP_DSC)*/ + USB_DESCRIPTOR_ENDPOINT, //Endpoint Descriptor + JOYSTICK_EP | _EP_IN, //EndpointAddress + _INTERRUPT, //Attributes + DESC_CONFIG_WORD(64), //size + 0x01, //Interval +}; + + +//Language code string descriptor +const struct{uint8_t bLength;uint8_t bDscType;uint16_t string[1];}sd000={ +sizeof(sd000),USB_DESCRIPTOR_STRING,{0x0409 +}}; + +//Manufacturer string descriptor +const struct{uint8_t bLength;uint8_t bDscType;uint16_t string[14];}sd001={ +sizeof(sd001),USB_DESCRIPTOR_STRING, +{'F','l','i','t','e','y',' ','D','e','s','i','g','n','s' +}}; + +//Product string descriptor +const struct{uint8_t bLength;uint8_t bDscType;uint16_t string[17];}sd002={ +sizeof(sd002),USB_DESCRIPTOR_STRING, +{'A','p','p','l','e',' ','I','I',' ','J','o','y','s','t','i','c','k' +}}; + +//Array of configuration descriptors +const uint8_t *const USB_CD_Ptr[]= +{ + (const uint8_t *const)&configDescriptor1 +}; + +//Array of string descriptors +const uint8_t *const USB_SD_Ptr[]= +{ + (const uint8_t *const)&sd000, + (const uint8_t *const)&sd001, + (const uint8_t *const)&sd002 +}; + +const struct{uint8_t report[HID_RPT01_SIZE];}hid_rpt01={{ + 0x05,0x01, //USAGE_PAGE (Generic Desktop) + 0x09,0x04, //USAGE (Game Pad) + 0xA1,0x01, //COLLECTION (Application) + 0x15,0x00, // LOGICAL_MINIMUM(0) + 0x25,0x01, // LOGICAL_MAXIMUM(1) + 0x35,0x00, // PHYSICAL_MINIMUM(0) + 0x45,0x01, // PHYSICAL_MAXIMUM(1) + 0x75,0x01, // REPORT_SIZE(1) + 0x95,0x02, // REPORT_COUNT(2) + 0x05,0x09, // USAGE_PAGE(Button) + 0x19,0x01, // USAGE_MINIMUM(Button 1) + 0x29,0x02, // USAGE_MAXIMUM(Button 2) + 0x81,0x02, // INPUT(Data,Var,Abs) + 0x95,0x06, // REPORT_COUNT(6) // filler + 0x81,0x01, // INPUT(Cnst,Ary,Abs) + 0x05,0x01, // USAGE_PAGE(Generic Desktop) + 0x26,0xFF,0x00, // LOGICAL_MAXIMUM(255) + 0x46,0xFF,0x00, // PHYSICAL_MAXIMUM(255) + 0x09,0x30, // USAGE(X) + 0x09,0x31, // USAGE(Y) + 0x75,0x08, // REPORT_SIZE(8) + 0x95,0x02, // REPORT_COUNT(2) + 0x81,0x02, // INPUT(Data,Var,Abs) + 0xC0 //END_COLLECTION +} +}; +/** EOF usb_descriptors.c ***************************************************/ + diff --git a/src/usb/usb_device.c b/src/usb/usb_device.c new file mode 100644 index 0000000..dd745c8 --- /dev/null +++ b/src/usb/usb_device.c @@ -0,0 +1,3129 @@ +// DOM-IGNORE-BEGIN +/******************************************************************************* +Copyright 2015 Microchip Technology Inc. (www.microchip.com) + +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. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ +//DOM-IGNORE-END + +/******************************************************************************* + USB Device Layer + + Company: + Microchip Technology Inc. + + File Name: + usb_device.c + + Summary: + Provides basic USB device functionality, including enumeration and USB + chapter 9 required behavior. + + Description: + Provides basic USB device functionality, including enumeration and USB + chapter 9 required behavior. +*******************************************************************************/ + +// ***************************************************************************** +// ***************************************************************************** +// Section: Included Files +// ***************************************************************************** +// ***************************************************************************** +#include + +#include +#include +#include + +#include "usb_config.h" + +#include "usb.h" +#include "usb_ch9.h" +#include "usb_device.h" +#include "usb_device_local.h" + +#ifndef uintptr_t + #if defined(__XC8__) || defined(__XC16__) + #define uintptr_t uint16_t + #elif defined (__XC32__) + #define uintptr_t uint32_t + #endif +#endif + +#if defined(USB_USE_MSD) + #include "usb_device_msd.h" +#endif + +// ***************************************************************************** +// ***************************************************************************** +// Section: File Scope or Global Constants +// ***************************************************************************** +// ***************************************************************************** +#if !defined(USE_USB_BUS_SENSE_IO) + //Assume the +5V VBUS is always present (like it would be in a bus powered + //only application), unless USE_USB_BUS_SENSE_IO and USB_BUS_SENSE have + //been properly defined elsewhere in the project. + #undef USB_BUS_SENSE + #define USB_BUS_SENSE 1 +#endif + +#if defined(USB_DEVICE_DISABLE_DTS_CHECKING) + #define _DTS_CHECKING_ENABLED 0 +#else + #define _DTS_CHECKING_ENABLED _DTSEN +#endif + +#if !defined(self_power) + //Assume the application is always bus powered, unless self_power has been + //defined elsewhere in the project + #define self_power 0 //0 = bus powered +#endif + +#if !defined(USB_MAX_NUM_CONFIG_DSC) + //Assume the application only implements one configuration descriptor, + //unless otherwise specified elsewhere in the project + #define USB_MAX_NUM_CONFIG_DSC 1 +#endif + +#if defined(__XC8) + //Suppress expected/harmless compiler warning message about unused RAM variables + //and certain function pointer usage. + //Certain variables and function pointers are not used if you don't use all + //of the USB stack APIs. However, these variables should not be + //removed (since they are still used/needed in some applications, and this + //is a common file shared by many projects, some of which rely on the "unused" + //variables/function pointers). + #pragma warning disable 1090 + #if __XC8_VERSION > 1300 + #pragma warning disable 1471 + #endif +#endif + +// ***************************************************************************** +// ***************************************************************************** +// Section: File Scope Data Types +// ***************************************************************************** +// ***************************************************************************** +typedef union +{ + uint8_t Val; + struct __PACKED + { + unsigned b0:1; + unsigned b1:1; + unsigned b2:1; + unsigned b3:1; + unsigned b4:1; + unsigned b5:1; + unsigned b6:1; + unsigned b7:1; + } bits; +} uint8_t_VAL, uint8_t_BITS; + +// ***************************************************************************** +// ***************************************************************************** +// Section: Variables +// ***************************************************************************** +// ***************************************************************************** +USB_VOLATILE USB_DEVICE_STATE USBDeviceState; +USB_VOLATILE uint8_t USBActiveConfiguration; +USB_VOLATILE uint8_t USBAlternateInterface[USB_MAX_NUM_INT]; +volatile BDT_ENTRY *pBDTEntryEP0OutCurrent; +volatile BDT_ENTRY *pBDTEntryEP0OutNext; +volatile BDT_ENTRY *pBDTEntryOut[USB_MAX_EP_NUMBER+1]; +volatile BDT_ENTRY *pBDTEntryIn[USB_MAX_EP_NUMBER+1]; +USB_VOLATILE uint8_t shortPacketStatus; +USB_VOLATILE uint8_t controlTransferState; +USB_VOLATILE IN_PIPE inPipes[1]; +USB_VOLATILE OUT_PIPE outPipes[1]; +USB_VOLATILE uint8_t *pDst; +USB_VOLATILE bool RemoteWakeup; +USB_VOLATILE bool USBBusIsSuspended; +USB_VOLATILE USTAT_FIELDS USTATcopy; +USB_VOLATILE uint8_t endpoint_number; +USB_VOLATILE bool BothEP0OutUOWNsSet; +USB_VOLATILE EP_STATUS ep_data_in[USB_MAX_EP_NUMBER+1]; +USB_VOLATILE EP_STATUS ep_data_out[USB_MAX_EP_NUMBER+1]; +USB_VOLATILE uint8_t USBStatusStageTimeoutCounter; +volatile bool USBDeferStatusStagePacket; +volatile bool USBStatusStageEnabledFlag1; +volatile bool USBStatusStageEnabledFlag2; +volatile bool USBDeferINDataStagePackets; +volatile bool USBDeferOUTDataStagePackets; +USB_VOLATILE uint32_t USB1msTickCount; +USB_VOLATILE uint8_t USBTicksSinceSuspendEnd; + +/** USB FIXED LOCATION VARIABLES ***********************************/ +#if defined(COMPILER_MPLAB_C18) + #pragma udata USB_BDT=USB_BDT_ADDRESS +#endif + +volatile BDT_ENTRY BDT[BDT_NUM_ENTRIES] BDT_BASE_ADDR_TAG; + +/******************************************************************** + * EP0 Buffer Space + *******************************************************************/ +volatile CTRL_TRF_SETUP SetupPkt CTRL_TRF_SETUP_ADDR_TAG; +volatile uint8_t CtrlTrfData[USB_EP0_BUFF_SIZE] CTRL_TRF_DATA_ADDR_TAG; + +/******************************************************************** + * non-EP0 Buffer Space + *******************************************************************/ +#if defined(USB_USE_MSD) + //Check if the MSD application specific USB endpoint buffer placement address + //macros have already been defined or not (ex: in a processor specific header) + //The msd_cbw and msd_csw buffers must be USB module accessible (and therefore + //must be at a certain address range on certain microcontrollers). + #if !defined(MSD_CBW_ADDR_TAG) + //Not previously defined. Assume in this case all microcontroller RAM is + //USB module accessible, and therefore, no specific address tag value is needed. + #define MSD_CBW_ADDR_TAG + #define MSD_CSW_ADDR_TAG + #endif + volatile USB_MSD_CBW msd_cbw MSD_CBW_ADDR_TAG; //Must be located in USB module accessible RAM + volatile USB_MSD_CSW msd_csw MSD_CSW_ADDR_TAG; //Must be located in USB module accessible RAM + + #if defined(__18CXX) || defined(__XC8) + volatile char msd_buffer[512] @ MSD_BUFFER_ADDRESS; + #else + volatile char msd_buffer[512]; + #endif +#endif + +//Depricated in v2.2 - will be removed in a future revision +#if !defined(USB_USER_DEVICE_DESCRIPTOR) + //Device descriptor + extern const USB_DEVICE_DESCRIPTOR device_dsc; +#else + USB_USER_DEVICE_DESCRIPTOR_INCLUDE; +#endif + +#if !defined(USB_USER_CONFIG_DESCRIPTOR) + //Array of configuration descriptors + extern const uint8_t *const USB_CD_Ptr[]; +#else + USB_USER_CONFIG_DESCRIPTOR_INCLUDE; +#endif + +extern const uint8_t *const USB_SD_Ptr[]; + + +// ***************************************************************************** +// ***************************************************************************** +// Section: Private and External Prototypes +// ***************************************************************************** +// ***************************************************************************** +extern bool USER_USB_CALLBACK_EVENT_HANDLER(USB_EVENT event, void *pdata, uint16_t size); + +static void USBCtrlEPService(void); +static void USBCtrlTrfSetupHandler(void); +static void USBCtrlTrfInHandler(void); +static void USBCheckStdRequest(void); +static void USBStdGetDscHandler(void); +static void USBCtrlEPServiceComplete(void); +static void USBCtrlTrfTxService(void); +static void USBCtrlTrfRxService(void); +static void USBStdSetCfgHandler(void); +static void USBStdGetStatusHandler(void); +static void USBStdFeatureReqHandler(void); +static void USBCtrlTrfOutHandler(void); +static void USBConfigureEndpoint(uint8_t EPNum, uint8_t direction); +static void USBWakeFromSuspend(void); +static void USBSuspend(void); +static void USBStallHandler(void); + +// ***************************************************************************** +// ***************************************************************************** +// Section: Macros or Functions +// ***************************************************************************** +// ***************************************************************************** + +/************************************************************************** + Function: + void USBDeviceInit(void) + + Description: + This function initializes the device stack it in the default state. The + USB module will be completely reset including all of the internal + variables, registers, and interrupt flags. + + Precondition: + This function must be called before any of the other USB Device + functions can be called, including USBDeviceTasks(). + + Parameters: + None + + Return Values: + None + + Remarks: + None + + ***************************************************************************/ +void USBDeviceInit(void) +{ + uint8_t i; + + USBDisableInterrupts(); + + //Make sure that if a GPIO output driver exists on VBUS, that it is + //tri-stated to avoid potential contention with the host + USB_HAL_VBUSTristate(); + + // Clear all USB error flags + USBClearInterruptRegister(U1EIR); + + // Clears all USB interrupts + USBClearInterruptRegister(U1IR); + + //Clear all of the endpoint control registers + U1EP0 = 0; + + DisableNonZeroEndpoints(USB_MAX_EP_NUMBER); + + SetConfigurationOptions(); + + //power up the module (if not already powered) + USBPowerModule(); + + //set the address of the BDT (if applicable) + USBSetBDTAddress(BDT); + + //Clear all of the BDT entries + for(i = 0; i < (sizeof(BDT)/sizeof(BDT_ENTRY)); i++) + { + BDT[i].Val = 0x00; + } + + // Assert reset request to all of the Ping Pong buffer pointers + USBPingPongBufferReset = 1; + + // Reset to default address + U1ADDR = 0x00; + + // Make sure packet processing is enabled + USBPacketDisable = 0; + + //Stop trying to reset ping pong buffer pointers + USBPingPongBufferReset = 0; + + // Flush any pending transactions + do + { + USBClearInterruptFlag(USBTransactionCompleteIFReg,USBTransactionCompleteIFBitNum); + //Initialize USB stack software state variables + inPipes[0].info.Val = 0; + outPipes[0].info.Val = 0; + outPipes[0].wCount.Val = 0; + }while(USBTransactionCompleteIF == 1); + + //Set flags to true, so the USBCtrlEPAllowStatusStage() function knows not to + //try and arm a status stage, even before the first control transfer starts. + USBStatusStageEnabledFlag1 = true; + USBStatusStageEnabledFlag2 = true; + //Initialize other flags + USBDeferINDataStagePackets = false; + USBDeferOUTDataStagePackets = false; + USBBusIsSuspended = false; + + //Initialize all pBDTEntryIn[] and pBDTEntryOut[] + //pointers to NULL, so they don't get used inadvertently. + for(i = 0; i < (uint8_t)(USB_MAX_EP_NUMBER+1u); i++) + { + pBDTEntryIn[i] = 0u; + pBDTEntryOut[i] = 0u; + ep_data_in[i].Val = 0u; + ep_data_out[i].Val = 0u; + } + + //Get ready for the first packet + pBDTEntryIn[0] = (volatile BDT_ENTRY*)&BDT[EP0_IN_EVEN]; + // Initialize EP0 as a Ctrl EP + U1EP0 = EP_CTRL|USB_HANDSHAKE_ENABLED; + //Prepare for the first SETUP on EP0 OUT + BDT[EP0_OUT_EVEN].ADR = ConvertToPhysicalAddress(&SetupPkt); + BDT[EP0_OUT_EVEN].CNT = USB_EP0_BUFF_SIZE; + BDT[EP0_OUT_EVEN].STAT.Val = _DAT0|_BSTALL; + BDT[EP0_OUT_EVEN].STAT.Val |= _USIE; + + // Clear active configuration + USBActiveConfiguration = 0; + + USB1msTickCount = 0; //Keeps track of total number of milliseconds since calling USBDeviceInit() when first initializing the USB module/stack code. + USBTicksSinceSuspendEnd = 0; //Keeps track of the number of milliseconds since a suspend condition has ended. + + //Indicate that we are now in the detached state + USBDeviceState = DETACHED_STATE; +} + + + +/************************************************************************** + Function: + void USBDeviceTasks(void) + + Summary: + This function is the main state machine/transaction handler of the USB + device side stack. When the USB stack is operated in "USB_POLLING" mode + (usb_config.h user option) the USBDeviceTasks() function should be called + periodically to receive and transmit packets through the stack. This + function also takes care of control transfers associated with the USB + enumeration process, and detecting various USB events (such as suspend). + This function should be called at least once every 1.8ms during the USB + enumeration process. After the enumeration process is complete (which can + be determined when USBGetDeviceState() returns CONFIGURED_STATE), the + USBDeviceTasks() handler may be called the faster of: either once + every 9.8ms, or as often as needed to make sure that the hardware USTAT + FIFO never gets full. A good rule of thumb is to call USBDeviceTasks() at + a minimum rate of either the frequency that USBTransferOnePacket() gets + called, or, once/1.8ms, whichever is faster. See the inline code comments + near the top of usb_device.c for more details about minimum timing + requirements when calling USBDeviceTasks(). + + When the USB stack is operated in "USB_INTERRUPT" mode, it is not necessary + to call USBDeviceTasks() from the main loop context. In the USB_INTERRUPT + mode, the USBDeviceTasks() handler only needs to execute when a USB + interrupt occurs, and therefore only needs to be called from the interrupt + context. + + Description: + This function is the main state machine/transaction handler of the USB + device side stack. When the USB stack is operated in "USB_POLLING" mode + (usb_config.h user option) the USBDeviceTasks() function should be called + periodically to receive and transmit packets through the stack. This + function also takes care of control transfers associated with the USB + enumeration process, and detecting various USB events (such as suspend). + This function should be called at least once every 1.8ms during the USB + enumeration process. After the enumeration process is complete (which can + be determined when USBGetDeviceState() returns CONFIGURED_STATE), the + USBDeviceTasks() handler may be called the faster of: either once + every 9.8ms, or as often as needed to make sure that the hardware USTAT + FIFO never gets full. A good rule of thumb is to call USBDeviceTasks() at + a minimum rate of either the frequency that USBTransferOnePacket() gets + called, or, once/1.8ms, whichever is faster. See the inline code comments + near the top of usb_device.c for more details about minimum timing + requirements when calling USBDeviceTasks(). + + When the USB stack is operated in "USB_INTERRUPT" mode, it is not necessary + to call USBDeviceTasks() from the main loop context. In the USB_INTERRUPT + mode, the USBDeviceTasks() handler only needs to execute when a USB + interrupt occurs, and therefore only needs to be called from the interrupt + context. + + Typical usage: + + void main(void) + { + USBDeviceInit(); + while(1) + { + USBDeviceTasks(); //Takes care of enumeration and other USB events + if((USBGetDeviceState() \< CONFIGURED_STATE) || + (USBIsDeviceSuspended() == true)) + { + //Either the device is not configured or we are suspended, + // so we don't want to execute any USB related application code + continue; //go back to the top of the while loop + } + else + { + //Otherwise we are free to run USB and non-USB related user + //application code. + UserApplication(); + } + } + } + + + Precondition: + Make sure the USBDeviceInit() function has been called prior to calling + USBDeviceTasks() for the first time. + Remarks: + USBDeviceTasks() does not need to be called while in the USB suspend mode, + if the user application firmware in the USBCBSuspend() callback function + enables the ACTVIF USB interrupt source and put the microcontroller into + sleep mode. If the application firmware decides not to sleep the + microcontroller core during USB suspend (ex: continues running at full + frequency, or clock switches to a lower frequency), then the USBDeviceTasks() + function must still be called periodically, at a rate frequent enough to + ensure the 10ms resume recovery interval USB specification is met. Assuming + a worst case primary oscillator and PLL start up time of less than 5ms, then + USBDeviceTasks() should be called once every 5ms in this scenario. + + When the USB cable is detached, or the USB host is not actively powering + the VBUS line to +5V nominal, the application firmware does not always have + to call USBDeviceTasks() frequently, as no USB activity will be taking + place. However, if USBDeviceTasks() is not called regularly, some + alternative means of promptly detecting when VBUS is powered (indicating + host attachment), or not powered (host powered down or USB cable unplugged) + is still needed. For self or dual self/bus powered USB applications, see + the USBDeviceAttach() and USBDeviceDetach() API documentation for additional + considerations. + ***************************************************************************/ +void USBDeviceTasks(void) +{ + uint8_t i; + + #ifdef USB_SUPPORT_OTG + //SRP Time Out Check + if (USBOTGSRPIsReady()) + { + if (USBT1MSECIF && USBT1MSECIE) + { + if (USBOTGGetSRPTimeOutFlag()) + { + if (USBOTGIsSRPTimeOutExpired()) + { + USB_OTGEventHandler(0,OTG_EVENT_SRP_FAILED,0,0); + } + } + + //Clear Interrupt Flag + USBClearInterruptFlag(USBT1MSECIFReg,USBT1MSECIFBitNum); + } + } + #endif + + #if defined(USB_POLLING) + //If the interrupt option is selected then the customer is required + // to notify the stack when the device is attached or removed from the + // bus by calling the USBDeviceAttach() and USBDeviceDetach() functions. + if (USB_BUS_SENSE != 1) + { + // Disable module & detach from bus + U1CON = 0; + + // Mask all USB interrupts + U1IE = 0; + + //Move to the detached state + USBDeviceState = DETACHED_STATE; + + #ifdef USB_SUPPORT_OTG + //Disable D+ Pullup + U1OTGCONbits.DPPULUP = 0; + + //Disable HNP + USBOTGDisableHnp(); + + //Deactivate HNP + USBOTGDeactivateHnp(); + + //If ID Pin Changed State + if (USBIDIF && USBIDIE) + { + //Re-detect & Initialize + USBOTGInitialize(); + + //Clear ID Interrupt Flag + USBClearInterruptFlag(USBIDIFReg,USBIDIFBitNum); + } + #endif + + #if defined __C30__ || defined __XC16__ + //USBClearInterruptFlag(U1OTGIR, 3); + #endif + //return so that we don't go through the rest of + //the state machine + USBClearUSBInterrupt(); + return; + } + + #ifdef USB_SUPPORT_OTG + //If Session Is Started Then + else + { + //If SRP Is Ready + if (USBOTGSRPIsReady()) + { + //Clear SRPReady + USBOTGClearSRPReady(); + + //Clear SRP Timeout Flag + USBOTGClearSRPTimeOutFlag(); + + //Indicate Session Started + UART2PrintString( "\r\n***** USB OTG B Event - Session Started *****\r\n" ); + } + } + #endif //#ifdef USB_SUPPORT_OTG + + //if we are in the detached state + if(USBDeviceState == DETACHED_STATE) + { + //Initialize register to known value + U1CON = 0; + + // Mask all USB interrupts + U1IE = 0; + + //Enable/set things like: pull ups, full/low-speed mode, + //set the ping pong mode, and set internal transceiver + SetConfigurationOptions(); + + // Enable module & attach to bus + while(!U1CONbits.USBEN){U1CONbits.USBEN = 1;} + + //moved to the attached state + USBDeviceState = ATTACHED_STATE; + + #ifdef USB_SUPPORT_OTG + U1OTGCON |= USB_OTG_DPLUS_ENABLE | USB_OTG_ENABLE; + #endif + } + #endif //#if defined(USB_POLLING) + + if(USBDeviceState == ATTACHED_STATE) + { + /* + * After enabling the USB module, it takes some time for the + * voltage on the D+ or D- line to rise high enough to get out + * of the SE0 condition. The USB Reset interrupt should not be + * unmasked until the SE0 condition is cleared. This helps + * prevent the firmware from misinterpreting this unique event + * as a USB bus reset from the USB host. + */ + + if(!USBSE0Event) + { + //We recently attached, make sure we are in a clean state + #if defined(__dsPIC33E__) || defined(_PIC24E__) || defined(__PIC32MM__) + U1IR = 0xFFEF; //Preserve IDLEIF info, so we can detect suspend + //during attach de-bounce interval + #else + USBClearInterruptRegister(U1IR); + #endif + + #if defined(USB_POLLING) + U1IE=0; // Mask all USB interrupts + #endif + USBResetIE = 1; // Unmask RESET interrupt + USBIdleIE = 1; // Unmask IDLE interrupt + USBDeviceState = POWERED_STATE; + } + } + + #ifdef USB_SUPPORT_OTG + //If ID Pin Changed State + if (USBIDIF && USBIDIE) + { + //Re-detect & Initialize + USBOTGInitialize(); + + USBClearInterruptFlag(USBIDIFReg,USBIDIFBitNum); + } + #endif + + /* + * Task A: Service USB Activity Interrupt + */ + if(USBActivityIF && USBActivityIE) + { + USBClearInterruptFlag(USBActivityIFReg,USBActivityIFBitNum); + #if defined(USB_SUPPORT_OTG) + U1OTGIR = 0x10; + #else + USBWakeFromSuspend(); + #endif + } + + /* + * Pointless to continue servicing if the device is in suspend mode. + */ + if(USBSuspendControl==1) + { + USBClearUSBInterrupt(); + return; + } + + /* + * Task B: Service USB Bus Reset Interrupt. + * When bus reset is received during suspend, ACTVIF will be set first, + * once the UCONbits.SUSPND is clear, then the URSTIF bit will be asserted. + * This is why URSTIF is checked after ACTVIF. + * + * The USB reset flag is masked when the USB state is in + * DETACHED_STATE or ATTACHED_STATE, and therefore cannot + * cause a USB reset event during these two states. + */ + if(USBResetIF && USBResetIE) + { + USBDeviceInit(); + + //Re-enable the interrupts since the USBDeviceInit() function will + // disable them. This will do nothing in a polling setup + USBUnmaskInterrupts(); + + USBDeviceState = DEFAULT_STATE; + + #ifdef USB_SUPPORT_OTG + //Disable HNP + USBOTGDisableHnp(); + + //Deactivate HNP + USBOTGDeactivateHnp(); + #endif + + USBClearInterruptFlag(USBResetIFReg,USBResetIFBitNum); + } + + /* + * Task C: Service other USB interrupts + */ + if(USBIdleIF && USBIdleIE) + { + #ifdef USB_SUPPORT_OTG + //If Suspended, Try to switch to Host + USBOTGSelectRole(ROLE_HOST); + USBClearInterruptFlag(USBIdleIFReg,USBIdleIFBitNum); + #else + USBSuspend(); + #endif + } + + #if defined(__XC16__) || defined(__C30__) || defined(__XC32__) + //Check if a 1ms interval has elapsed. + if(USBT1MSECIF) + { + USBClearInterruptFlag(USBT1MSECIFReg, USBT1MSECIFBitNum); + USBIncrement1msInternalTimers(); + } + #endif + + //Start-of-Frame Interrupt + if(USBSOFIF) + { + //Call the user SOF event callback if enabled. + if(USBSOFIE) + { + USB_SOF_HANDLER(EVENT_SOF,0,1); + } + USBClearInterruptFlag(USBSOFIFReg,USBSOFIFBitNum); + + #if defined(__XC8__) || defined(__C18__) + USBIncrement1msInternalTimers(); + #endif + + #if defined(USB_ENABLE_STATUS_STAGE_TIMEOUTS) + //Supporting this feature requires a 1ms time base for keeping track of the timeout interval. + #if(USB_SPEED_OPTION == USB_LOW_SPEED) + #warning "Double click this message. See inline code comments." + //The "USB_ENABLE_STATUS_STAGE_TIMEOUTS" feature is optional and is + //not strictly needed in all applications (ex: those that never call + //USBDeferStatusStage() and don't use host to device (OUT) control + //transfers with data stage). + //However, if this feature is enabled and used in a low speed application, + //it is required for the application code to periodically call the + //USBIncrement1msInternalTimers() function at a nominally 1ms rate. + #endif + + //Decrement our status stage counter. + if(USBStatusStageTimeoutCounter != 0u) + { + USBStatusStageTimeoutCounter--; + } + //Check if too much time has elapsed since progress was made in + //processing the control transfer, without arming the status stage. + //If so, auto-arm the status stage to ensure that the control + //transfer can [eventually] complete, within the timing limits + //dictated by section 9.2.6 of the official USB 2.0 specifications. + if(USBStatusStageTimeoutCounter == 0) + { + USBCtrlEPAllowStatusStage(); //Does nothing if the status stage was already armed. + } + #endif + } + + if(USBStallIF && USBStallIE) + { + USBStallHandler(); + } + + if(USBErrorIF && USBErrorIE) + { + USB_ERROR_HANDLER(EVENT_BUS_ERROR,0,1); + USBClearInterruptRegister(U1EIR); // This clears UERRIF + + //On PIC18, clearing the source of the error will automatically clear + // the interrupt flag. On other devices the interrupt flag must be + // manually cleared. + #if defined(__C32__) || defined(__C30__) || defined __XC16__ + USBClearInterruptFlag( USBErrorIFReg, USBErrorIFBitNum ); + #endif + } + + /* + * Pointless to continue servicing if the host has not sent a bus reset. + * Once bus reset is received, the device transitions into the DEFAULT + * state and is ready for communication. + */ + if(USBDeviceState < DEFAULT_STATE) + { + USBClearUSBInterrupt(); + return; + } + + /* + * Task D: Servicing USB Transaction Complete Interrupt + */ + if(USBTransactionCompleteIE) + { + for(i = 0; i < 4u; i++) //Drain or deplete the USAT FIFO entries. If the USB FIFO ever gets full, USB bandwidth + { //utilization can be compromised, and the device won't be able to receive SETUP packets. + if(USBTransactionCompleteIF) + { + //Save and extract USTAT register info. Will use this info later. + USTATcopy.Val = U1STAT; + endpoint_number = USBHALGetLastEndpoint(USTATcopy); + + USBClearInterruptFlag(USBTransactionCompleteIFReg,USBTransactionCompleteIFBitNum); + + //Keep track of the hardware ping pong state for endpoints other + //than EP0, if ping pong buffering is enabled. + #if (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0) || (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG) + if(USBHALGetLastDirection(USTATcopy) == OUT_FROM_HOST) + { + ep_data_out[endpoint_number].bits.ping_pong_state ^= 1; + } + else + { + ep_data_in[endpoint_number].bits.ping_pong_state ^= 1; + } + #endif + + //USBCtrlEPService only services transactions over EP0. + //It ignores all other EP transactions. + if(endpoint_number == 0) + { + USBCtrlEPService(); + } + else + { + USB_TRANSFER_COMPLETE_HANDLER(EVENT_TRANSFER, (uint8_t*)&USTATcopy.Val, 0); + } + }//end if(USBTransactionCompleteIF) + else + { + break; //USTAT FIFO must be empty. + } + }//end for() + }//end if(USBTransactionCompleteIE) + + USBClearUSBInterrupt(); +}//end of USBDeviceTasks() + +/******************************************************************************* + Function: + void USBEnableEndpoint(uint8_t ep, uint8_t options) + + Summary: + This function will enable the specified endpoint with the specified + options + Description: + This function will enable the specified endpoint with the specified + options. + + Typical Usage: + + void USBCBInitEP(void) + { + USBEnableEndpoint(MSD_DATA_IN_EP,USB_IN_ENABLED|USB_OUT_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP); + USBMSDInit(); + } + + + In the above example endpoint number MSD_DATA_IN_EP is being configured + for both IN and OUT traffic with handshaking enabled. Also since + MSD_DATA_IN_EP is not endpoint 0 (MSD does not allow this), then we can + explicitly disable SETUP packets on this endpoint. + Conditions: + None + Input: + uint8_t ep - the endpoint to be configured + uint8_t options - optional settings for the endpoint. The options should + be ORed together to form a single options string. The + available optional settings for the endpoint. The + options should be ORed together to form a single options + string. The available options are the following\: + * USB_HANDSHAKE_ENABLED enables USB handshaking (ACK, + NAK) + * USB_HANDSHAKE_DISABLED disables USB handshaking (ACK, + NAK) + * USB_OUT_ENABLED enables the out direction + * USB_OUT_DISABLED disables the out direction + * USB_IN_ENABLED enables the in direction + * USB_IN_DISABLED disables the in direction + * USB_ALLOW_SETUP enables control transfers + * USB_DISALLOW_SETUP disables control transfers + * USB_STALL_ENDPOINT STALLs this endpoint + Return: + None + Remarks: + None + *****************************************************************************/ +void USBEnableEndpoint(uint8_t ep, uint8_t options) +{ + unsigned char* p; + + //Use USBConfigureEndpoint() to set up the pBDTEntryIn/Out[ep] pointer and + //starting DTS state in the BDT entry. + if(options & USB_OUT_ENABLED) + { + USBConfigureEndpoint(ep, OUT_FROM_HOST); + } + if(options & USB_IN_ENABLED) + { + USBConfigureEndpoint(ep, IN_TO_HOST); + } + + //Update the relevant UEPx register to actually enable the endpoint with + //the specified options (ex: handshaking enabled, control transfers allowed, + //etc.) + #if defined(__C32__) + p = (unsigned char*)(&U1EP0+(4*ep)); + #else + p = (unsigned char*)(&U1EP0+ep); + #endif + *p = options; +} + + +/************************************************************************* + Function: + USB_HANDLE USBTransferOnePacket(uint8_t ep, uint8_t dir, uint8_t* data, uint8_t len) + + Summary: + Transfers a single packet (one transaction) of data on the USB bus. + + Description: + The USBTransferOnePacket() function prepares a USB endpoint + so that it may send data to the host (an IN transaction), or + receive data from the host (an OUT transaction). The + USBTransferOnePacket() function can be used both to receive and + send data to the host. This function is the primary API function + provided by the USB stack firmware for sending or receiving application + data over the USB port. + + The USBTransferOnePacket() is intended for use with all application + endpoints. It is not used for sending or receiving application data + through endpoint 0 by using control transfers. Separate API + functions, such as USBEP0Receive(), USBEP0SendRAMPtr(), and + USBEP0SendROMPtr() are provided for this purpose. + + The USBTransferOnePacket() writes to the Buffer Descriptor Table (BDT) + entry associated with an endpoint buffer, and sets the UOWN bit, which + prepares the USB hardware to allow the transaction to complete. The + application firmware can use the USBHandleBusy() macro to check the + status of the transaction, to see if the data has been successfully + transmitted yet. + + + Typical Usage + + //make sure that the we are in the configured state + if(USBGetDeviceState() == CONFIGURED_STATE) + { + //make sure that the last transaction isn't busy by checking the handle + if(!USBHandleBusy(USBInHandle)) + { + //Write the new data that we wish to send to the host to the INPacket[] array + INPacket[0] = USEFUL_APPLICATION_VALUE1; + INPacket[1] = USEFUL_APPLICATION_VALUE2; + //INPacket[2] = ... (fill in the rest of the packet data) + + //Send the data contained in the INPacket[] array through endpoint "EP_NUM" + USBInHandle = USBTransferOnePacket(EP_NUM,IN_TO_HOST,(uint8_t*)&INPacket[0],sizeof(INPacket)); + } + } + + + Conditions: + Before calling USBTransferOnePacket(), the following should be true. + 1. The USB stack has already been initialized (USBDeviceInit() was called). + 2. A transaction is not already pending on the specified endpoint. This + is done by checking the previous request using the USBHandleBusy() + macro (see the typical usage example). + 3. The host has already sent a set configuration request and the + enumeration process is complete. + This can be checked by verifying that the USBGetDeviceState() + macro returns "CONFIGURED_STATE", prior to calling + USBTransferOnePacket(). + + Input: + uint8_t ep - The endpoint number that the data will be transmitted or + received on + uint8_t dir - The direction of the transfer + This value is either OUT_FROM_HOST or IN_TO_HOST + uint8_t* data - For IN transactions: pointer to the RAM buffer containing + the data to be sent to the host. For OUT transactions: pointer + to the RAM buffer that the received data should get written to. + uint8_t len - Length of the data needing to be sent (for IN transactions). + For OUT transactions, the len parameter should normally be set + to the endpoint size specified in the endpoint descriptor. + + Return Values: + USB_HANDLE - handle to the transfer. The handle is a pointer to + the BDT entry associated with this transaction. The + status of the transaction (ex: if it is complete or still + pending) can be checked using the USBHandleBusy() macro + and supplying the USB_HANDLE provided by + USBTransferOnePacket(). + + Remarks: + If calling the USBTransferOnePacket() function from within the USBCBInitEP() + callback function, the set configuration is still being processed and the + USBDeviceState may not be == CONFIGURED_STATE yet. In this special case, + the USBTransferOnePacket() may still be called, but make sure that the + endpoint has been enabled and initialized by the USBEnableEndpoint() + function first. + + *************************************************************************/ +USB_HANDLE USBTransferOnePacket(uint8_t ep,uint8_t dir,uint8_t* data,uint8_t len) +{ + volatile BDT_ENTRY* handle; + + //If the direction is IN + if(dir != 0) + { + //point to the IN BDT of the specified endpoint + handle = pBDTEntryIn[ep]; + } + else + { + //else point to the OUT BDT of the specified endpoint + handle = pBDTEntryOut[ep]; + } + + //Error checking code. Make sure the handle (pBDTEntryIn[ep] or + //pBDTEntryOut[ep]) is initialized before using it. + if(handle == 0) + { + return 0; + } + + //Toggle the DTS bit if required + #if (USB_PING_PONG_MODE == USB_PING_PONG__NO_PING_PONG) + handle->STAT.Val ^= _DTSMASK; + #elif (USB_PING_PONG_MODE == USB_PING_PONG__EP0_OUT_ONLY) + if(ep != 0) + { + handle->STAT.Val ^= _DTSMASK; + } + #endif + + //Set the data pointer, data length, and enable the endpoint + handle->ADR = ConvertToPhysicalAddress(data); + handle->CNT = len; + handle->STAT.Val &= _DTSMASK; + handle->STAT.Val |= (_DTSEN & _DTS_CHECKING_ENABLED); + handle->STAT.Val |= _USIE; + + //Point to the next buffer for ping pong purposes. + if(dir != OUT_FROM_HOST) + { + //toggle over the to the next buffer for an IN endpoint + pBDTEntryIn[ep] = (BDT_ENTRY*)(((uintptr_t)pBDTEntryIn[ep]) ^ USB_NEXT_PING_PONG); + } + else + { + //toggle over the to the next buffer for an OUT endpoint + pBDTEntryOut[ep] = (BDT_ENTRY*)(((uintptr_t)pBDTEntryOut[ep]) ^ USB_NEXT_PING_PONG); + } + return (USB_HANDLE)handle; +} + + +/******************************************************************** + Function: + void USBStallEndpoint(uint8_t ep, uint8_t dir) + + Summary: + Configures the specified endpoint to send STALL to the host, the next + time the host tries to access the endpoint. + + PreCondition: + None + + Parameters: + uint8_t ep - The endpoint number that should be configured to send STALL. + uint8_t dir - The direction of the endpoint to STALL, either + IN_TO_HOST or OUT_FROM_HOST. + + Return Values: + None + + Remarks: + None + + *******************************************************************/ +void USBStallEndpoint(uint8_t ep, uint8_t dir) +{ + BDT_ENTRY *p; + + if(ep == 0) + { + //For control endpoints (ex: EP0), we need to STALL both IN and OUT + //endpoints. EP0 OUT must also be prepared to receive the next SETUP + //packet that will arrive. + pBDTEntryEP0OutNext->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress(&SetupPkt); + pBDTEntryEP0OutNext->STAT.Val = _DAT0|(_DTSEN & _DTS_CHECKING_ENABLED)|_BSTALL; + pBDTEntryEP0OutNext->STAT.Val |= _USIE; + pBDTEntryIn[0]->STAT.Val = _BSTALL; + pBDTEntryIn[0]->STAT.Val |= _USIE; + + } + else + { + p = (BDT_ENTRY*)(&BDT[EP(ep,dir,0)]); + p->STAT.Val |= _BSTALL; + p->STAT.Val |= _USIE; + + //If the device is in FULL or ALL_BUT_EP0 ping pong modes + //then stall that entry as well + #if (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG) || (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0) + p = (BDT_ENTRY*)(&BDT[EP(ep,dir,1)]); + p->STAT.Val |= _BSTALL; + p->STAT.Val |= _USIE; + #endif + } +} + +/************************************************************************** + Function: + void USBCancelIO(uint8_t endpoint) + + Description: + This function cancels the transfers pending on the specified endpoint. + This function can only be used after a SETUP packet is received and + before that setup packet is handled. This is the time period in which + the EVENT_EP0_REQUEST is thrown, before the event handler function + returns to the stack. + + Precondition: + + Parameters: + uint8_t endpoint - the endpoint number you wish to cancel the transfers for + + Return Values: + None + + Remarks: + None + + **************************************************************************/ +void USBCancelIO(uint8_t endpoint) +{ + if(USBPacketDisable == 1) + { + //The PKTDIS bit is currently set right now. It is therefore "safe" + //to mess with the BDT right now. + pBDTEntryIn[endpoint]->Val &= _DTSMASK; //Makes UOWN = 0 (_UCPU mode). Deactivates endpoint. Only sends NAKs. + pBDTEntryIn[endpoint]->Val ^= _DTSMASK; //Toggle the DTS bit. This packet didn't get sent yet, and the next call to USBTransferOnePacket() will re-toggle the DTS bit back to the original (correct) value. + + //Need to do additional handling if ping-pong buffering is being used + #if ((USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG) || (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0)) + //Point to the next buffer for ping pong purposes. UOWN getting cleared + //(either due to SIE clearing it after a transaction, or the firmware + //clearing it) makes hardware ping pong pointer advance. + pBDTEntryIn[endpoint] = (BDT_ENTRY*)(((uintptr_t)pBDTEntryIn[endpoint]) ^ USB_NEXT_PING_PONG); + + pBDTEntryIn[endpoint]->STAT.Val &= _DTSMASK; + pBDTEntryIn[endpoint]->STAT.Val ^= _DTSMASK; + #endif + } +} + +/************************************************************************** + Function: + void USBDeviceDetach(void) + + Summary: + This function configures the USB module to "soft detach" itself from + the USB host. + + Description: + This function configures the USB module to perform a "soft detach" + operation, by disabling the D+ (or D-) ~1.5k pull up resistor, which + lets the host know the device is present and attached. This will make + the host think that the device has been unplugged. This is potentially + useful, as it allows the USB device to force the host to re-enumerate + the device (on the firmware has re-enabled the USB module/pull up, by + calling USBDeviceAttach(), to "soft re-attach" to the host). + + Precondition: + Should only be called when USB_INTERRUPT is defined. See remarks + section if USB_POLLING mode option is being used (usb_config.h option). + + Additionally, this function should only be called from the main() loop + context. Do not call this function from within an interrupt handler, as + this function may modify global interrupt enable bits and settings. + + Parameters: + None + + Return Values: + None + + Remarks: + If the application firmware calls USBDeviceDetach(), it is strongly + recommended that the firmware wait at least >= 80ms before calling + USBDeviceAttach(). If the firmware performs a soft detach, and then + re-attaches too soon (ex: after a few micro seconds for instance), some + hosts may interpret this as an unexpected "glitch" rather than as a + physical removal/re-attachment of the USB device. In this case the host + may simply ignore the event without re-enumerating the device. To + ensure that the host properly detects and processes the device soft + detach/re-attach, it is recommended to make sure the device remains + detached long enough to mimic a real human controlled USB + unplug/re-attach event (ex: after calling USBDeviceDetach(), do not + call USBDeviceAttach() for at least 80+ms, preferably longer. + + Neither the USBDeviceDetach() or USBDeviceAttach() functions are blocking + or take long to execute. It is the application firmwares + responsibility for adding the 80+ms delay, when using these API + functions. + + Note: The Windows plug and play event handler processing is fairly + slow, especially in certain versions of Windows, and for certain USB + device classes. It has been observed that some device classes need to + provide even more USB detach dwell interval (before calling + USBDeviceAttach()), in order to work correctly after re-enumeration. + If the USB device is a CDC class device, it is recommended to wait + at least 1.5 seconds or longer, before soft re-attaching to the host, + to provide the plug and play event handler enough time to finish + processing the removal event, before the re-attach occurs. + + If the application is using the USB_POLLING mode option, then the + USBDeviceDetach() and USBDeviceAttach() functions are not available. + In this mode, the USB stack relies on the "#define USE_USB_BUS_SENSE_IO" + and "#define USB_BUS_SENSE" options in the + HardwareProfile – [platform name].h file. + + When using the USB_POLLING mode option, and the + "#define USE_USB_BUS_SENSE_IO" definition has been commented out, then + the USB stack assumes that it should always enable the USB module at + pretty much all times. Basically, anytime the application firmware + calls USBDeviceTasks(), the firmware will automatically enable the USB + module. This mode would typically be selected if the application was + designed to be a purely bus powered device. In this case, the + application is powered from the +5V VBUS supply from the USB port, so + it is correct and sensible in this type of application to power up and + turn on the USB module, at anytime that the microcontroller is + powered (which implies the USB cable is attached and the host is also + powered). + + In a self powered application, the USB stack is designed with the + intention that the user will enable the "#define USE_USB_BUS_SENSE_IO" + option in the HardwareProfile – [platform name].h file. When this + option is defined, then the USBDeviceTasks() function will automatically + check the I/O pin port value of the designated pin (based on the + #define USB_BUS_SENSE option in the HardwareProfile – [platform name].h + file), every time the application calls USBDeviceTasks(). If the + USBDeviceTasks() function is executed and finds that the pin defined by + the #define USB_BUS_SENSE is in a logic low state, then it will + automatically disable the USB module and tri-state the D+ and D- pins. + If however the USBDeviceTasks() function is executed and finds the pin + defined by the #define USB_BUS_SENSE is in a logic high state, then it + will automatically enable the USB module, if it has not already been + enabled. + + **************************************************************************/ +#if defined(USB_INTERRUPT) +void USBDeviceDetach(void) +{ + //If the interrupt option is selected then the customer is required + // to notify the stack when the device is attached or removed from the + // bus by calling the USBDeviceAttach() and USBDeviceDetach() functions. +#ifdef USB_SUPPORT_OTG + if (USB_BUS_SENSE != 1) +#endif + { + // Disable module & detach from bus + U1CON = 0; + + // Mask all USB interrupts + U1IE = 0; + + //Move to the detached state + USBDeviceState = DETACHED_STATE; + + #ifdef USB_SUPPORT_OTG + //Disable D+ Pull-up + U1OTGCONbits.DPPULUP = 0; + + //Disable HNP + USBOTGDisableHnp(); + + //Deactivate HNP + USBOTGDeactivateHnp(); + + //If ID Pin Changed State + if (USBIDIF && USBIDIE) + { + //Re-detect & Initialize + USBOTGInitialize(); + + //Clear ID Interrupt Flag + USBClearInterruptFlag(USBIDIFReg,USBIDIFBitNum); + } + #endif + + #if defined __C30__ || defined __XC16__ + //USBClearInterruptFlag(U1OTGIR, 3); + #endif + //return so that we don't go through the rest of + //the state machine + return; + } + +#ifdef USB_SUPPORT_OTG + //If Session Is Started Then + else + { + //If SRP Is Ready + if (USBOTGSRPIsReady()) + { + //Clear SRPReady + USBOTGClearSRPReady(); + + //Clear SRP Timeout Flag + USBOTGClearSRPTimeOutFlag(); + + //Indicate Session Started + UART2PrintString( "\r\n***** USB OTG B Event - Session Started *****\r\n" ); + } + } +#endif +} +#endif //#if defined(USB_INTERRUPT) +/************************************************************************** + Function: + void USBDeviceAttach(void) + + Summary: + Checks if VBUS is present, and that the USB module is not already + initialized, and if so, enables the USB module so as to signal device + attachment to the USB host. + + Description: + This function indicates to the USB host that the USB device has been + attached to the bus. This function needs to be called in order for the + device to start to enumerate on the bus. + + Precondition: + Should only be called when USB_INTERRUPT is defined. Also, should only + be called from the main() loop context. Do not call USBDeviceAttach() + from within an interrupt handler, as the USBDeviceAttach() function + may modify global interrupt enable bits and settings. + + For normal USB devices: + Make sure that if the module was previously on, that it has been turned off + for a long time (ex: 100ms+) before calling this function to re-enable the module. + If the device turns off the D+ (for full speed) or D- (for low speed) ~1.5k ohm + pull up resistor, and then turns it back on very quickly, common hosts will sometimes + reject this event, since no human could ever unplug and re-attach a USB device in a + microseconds (or nanoseconds) timescale. The host could simply treat this as some kind + of glitch and ignore the event altogether. + Parameters: + None + + Return Values: + None + + Remarks: + See also the USBDeviceDetach() API function documentation. +****************************************************************************/ +#if defined(USB_INTERRUPT) +void USBDeviceAttach(void) +{ + //if we are in the detached state + if(USBDeviceState == DETACHED_STATE) + { + if(USB_BUS_SENSE == 1) + { + //Initialize registers to known states. + U1CON = 0; + + // Mask all USB interrupts + U1IE = 0; + + //Configure things like: pull ups, full/low-speed mode, + //set the ping pong mode, and set internal transceiver + SetConfigurationOptions(); + + USBEnableInterrupts(); //Modifies global interrupt settings + + // Enable module & attach to bus + while(!U1CONbits.USBEN){U1CONbits.USBEN = 1;} + + //moved to the attached state + USBDeviceState = ATTACHED_STATE; + + #ifdef USB_SUPPORT_OTG + U1OTGCON = USB_OTG_DPLUS_ENABLE | USB_OTG_ENABLE; + #endif + } + } +} +#endif //#if defined(USB_INTERRUPT) + + +/******************************************************************************* + Function: void USBCtrlEPAllowStatusStage(void); + + Summary: This function prepares the proper endpoint 0 IN or endpoint 0 OUT + (based on the controlTransferState) to allow the status stage packet + of a control transfer to complete. This function gets used + internally by the USB stack itself, but it may also be called from + the application firmware, IF the application firmware called + the USBDeferStatusStage() function during the initial processing + of the control transfer request. In this case, the application + must call the USBCtrlEPAllowStatusStage() once, after it has fully + completed processing and handling the data stage portion of the + request. + + If the application firmware has no need for delaying control + transfers, and therefore never calls USBDeferStatusStage(), then the + application firmware should not call USBCtrlEPAllowStatusStage(). + + Description: + + Conditions: + None + + Input: + + Return: + + Remarks: + None + *****************************************************************************/ +void USBCtrlEPAllowStatusStage(void) +{ + //Check and set two flags, prior to actually modifying any BDT entries. + //This double checking is necessary to make certain that + //USBCtrlEPAllowStatusStage() can be called twice simultaneously (ex: once + //in main loop context, while simultaneously getting an interrupt which + //tries to call USBCtrlEPAllowStatusStage() again, at the same time). + if(USBStatusStageEnabledFlag1 == false) + { + USBStatusStageEnabledFlag1 = true; + if(USBStatusStageEnabledFlag2 == false) + { + USBStatusStageEnabledFlag2 = true; + + //Determine which endpoints (EP0 IN or OUT needs arming for the status + //stage), based on the type of control transfer currently pending. + if(controlTransferState == CTRL_TRF_RX) + { + pBDTEntryIn[0]->CNT = 0; + pBDTEntryIn[0]->STAT.Val = _DAT1|(_DTSEN & _DTS_CHECKING_ENABLED); + pBDTEntryIn[0]->STAT.Val |= _USIE; + } + else if(controlTransferState == CTRL_TRF_TX) + { + BothEP0OutUOWNsSet = false; //Indicator flag used in USBCtrlTrfOutHandler() + + //This buffer (when ping pong buffering is enabled on EP0 OUT) receives the + //next SETUP packet. + #if((USB_PING_PONG_MODE == USB_PING_PONG__EP0_OUT_ONLY) || (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG)) + pBDTEntryEP0OutCurrent->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutCurrent->ADR = ConvertToPhysicalAddress(&SetupPkt); + pBDTEntryEP0OutCurrent->STAT.Val = _BSTALL; //Prepare endpoint to accept a SETUP transaction + pBDTEntryEP0OutCurrent->STAT.Val |= _USIE; + BothEP0OutUOWNsSet = true; //Indicator flag used in USBCtrlTrfOutHandler() + #endif + + //This EP0 OUT buffer receives the 0-byte OUT status stage packet. + pBDTEntryEP0OutNext->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress(&SetupPkt); + pBDTEntryEP0OutNext->STAT.Val = _USIE; // Note: DTSEN is 0 + } + } + } +} + + +/******************************************************************************* + Function: void USBCtrlEPAllowDataStage(void); + + Summary: This function allows the data stage of either a host-to-device or + device-to-host control transfer (with data stage) to complete. + This function is meant to be used in conjunction with either the + USBDeferOUTDataStage() or USBDeferINDataStage(). If the firmware + does not call either USBDeferOUTDataStage() or USBDeferINDataStage(), + then the firmware does not need to manually call + USBCtrlEPAllowDataStage(), as the USB stack will call this function + instead. + + Description: + + Conditions: A control transfer (with data stage) should already be pending, + if the firmware calls this function. Additionally, the firmware + should have called either USBDeferOUTDataStage() or + USBDeferINDataStage() at the start of the control transfer, if + the firmware will be calling this function manually. + + Input: + + Return: + + Remarks: + *****************************************************************************/ +void USBCtrlEPAllowDataStage(void) +{ + USBDeferINDataStagePackets = false; + USBDeferOUTDataStagePackets = false; + + if(controlTransferState == CTRL_TRF_RX) //(...) + { + //Prepare EP0 OUT to receive the first OUT data packet in the data stage sequence. + pBDTEntryEP0OutNext->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress(&CtrlTrfData); + pBDTEntryEP0OutNext->STAT.Val = _DAT1|(_DTSEN & _DTS_CHECKING_ENABLED); + pBDTEntryEP0OutNext->STAT.Val |= _USIE; + } + else //else must be controlTransferState == CTRL_TRF_TX (...) + { + //Error check the data stage byte count. Make sure the user specified + //value was no greater than the number of bytes the host requested. + if(SetupPkt.wLength < inPipes[0].wCount.Val) + { + inPipes[0].wCount.Val = SetupPkt.wLength; + } + USBCtrlTrfTxService(); //Copies one IN data packet worth of data from application buffer + //to CtrlTrfData buffer. Also keeps track of how many bytes remaining. + + //Cnt should have been initialized by responsible request owner (ex: by + //using the USBEP0SendRAMPtr() or USBEP0SendROMPtr() API function). + pBDTEntryIn[0]->ADR = ConvertToPhysicalAddress(&CtrlTrfData); + pBDTEntryIn[0]->STAT.Val = _DAT1|(_DTSEN & _DTS_CHECKING_ENABLED); + pBDTEntryIn[0]->STAT.Val |= _USIE; + } +} + + +/******************************************************************************/ +/** Internal Functions *********************************************************/ +/******************************************************************************/ + +/******************************************************************** + * Function: void USBConfigureEndpoint(uint8_t EPNum, uint8_t direction) + * + * PreCondition: None + * + * Input: uint8_t EPNum - the endpoint to be configured + * uint8_t direction - the direction to be configured + * (either OUT_FROM_HOST or IN_TO_HOST) + * + * Output: None + * + * Side Effects: None + * + * Overview: This function will configure the specified + * endpoint + * + * Note: None + *******************************************************************/ +static void USBConfigureEndpoint(uint8_t EPNum, uint8_t direction) +{ + volatile BDT_ENTRY* handle; + + //Compute a pointer to the even BDT entry corresponding to the + //EPNum and direction values passed to this function. + handle = (volatile BDT_ENTRY*)&BDT[EP0_OUT_EVEN]; //Get address of start of BDT + handle += EP(EPNum,direction,0u); //Add in offset to the BDT of interest + + handle->STAT.UOWN = 0; //mostly redundant, since USBStdSetCfgHandler() + //already cleared the entire BDT table + + //Make sure our pBDTEntryIn/Out[] pointer is initialized. Needed later + //for USBTransferOnePacket() API calls. + if(direction == OUT_FROM_HOST) + { + pBDTEntryOut[EPNum] = handle; + } + else + { + pBDTEntryIn[EPNum] = handle; + } + + #if (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG) + handle->STAT.DTS = 0; + (handle+1)->STAT.DTS = 1; + #elif (USB_PING_PONG_MODE == USB_PING_PONG__NO_PING_PONG) + //Set DTS to one because the first thing we will do + //when transmitting is toggle the bit + handle->STAT.DTS = 1; + #elif (USB_PING_PONG_MODE == USB_PING_PONG__EP0_OUT_ONLY) + if(EPNum != 0) + { + handle->STAT.DTS = 1; + } + #elif (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0) + if(EPNum != 0) + { + handle->STAT.DTS = 0; + (handle+1)->STAT.DTS = 1; + } + #endif +} + + +/****************************************************************************** + * Function: void USBCtrlEPServiceComplete(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine wrap up the remaining tasks in servicing + * a Setup Request. Its main task is to set the endpoint + * controls appropriately for a given situation. See code + * below. + * There are three main scenarios: + * a) There was no handler for the Request, in this case + * a STALL should be sent out. + * b) The host has requested a read control transfer, + * endpoints are required to be setup in a specific way. + * c) The host has requested a write control transfer, or + * a control data stage is not required, endpoints are + * required to be setup in a specific way. + * + * Packet processing is resumed by clearing PKTDIS bit. + * + * Note: None + *****************************************************************************/ +static void USBCtrlEPServiceComplete(void) +{ + /* + * PKTDIS bit is set when a Setup Transaction is received. + * Clear to resume packet processing. + */ + USBPacketDisable = 0; + + //Check the busy bits and the SetupPtk.DataDir variables to determine what type of + //control transfer is currently in progress. We need to know the type of control + //transfer that is currently pending, in order to know how to properly arm the + //EP0 IN and EP0 OUT endpoints. + if(inPipes[0].info.bits.busy == 0) + { + if(outPipes[0].info.bits.busy == 1) + { + controlTransferState = CTRL_TRF_RX; + /* + * Control Write: + * ... | + */ + + //1. Prepare OUT EP to receive data, unless a USB class request handler + // function decided to defer the data stage (ex: because the intended + // RAM buffer wasn't available yet) by calling USBDeferDataStage(). + // If it did so, it is then responsible for calling USBCtrlEPAllowDataStage(), + // once it is ready to begin receiving the data. + if(USBDeferOUTDataStagePackets == false) + { + USBCtrlEPAllowDataStage(); + } + + //2. IN endpoint 0 status stage will be armed by USBCtrlEPAllowStatusStage() + //after all of the OUT data has been received and consumed, or if a timeout occurs. + USBStatusStageEnabledFlag2 = false; + USBStatusStageEnabledFlag1 = false; + } + else + { + /* + * If no one knows how to service this request then stall. + * Must also prepare EP0 to receive the next SETUP transaction. + */ + pBDTEntryEP0OutNext->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress(&SetupPkt); + pBDTEntryEP0OutNext->STAT.Val = _DAT0|(_DTSEN & _DTS_CHECKING_ENABLED)|_BSTALL; + pBDTEntryEP0OutNext->STAT.Val |= _USIE; + pBDTEntryIn[0]->STAT.Val = _BSTALL; + pBDTEntryIn[0]->STAT.Val |= _USIE; + } + } + else // A module has claimed ownership of the control transfer session. + { + if(SetupPkt.DataDir == USB_SETUP_DEVICE_TO_HOST_BITFIELD) + { + controlTransferState = CTRL_TRF_TX; + /* + * Control Read: + * ... | + * + * 1. Prepare IN EP to transfer data to the host. If however the data + * wasn't ready yet (ex: because the firmware needs to go and read it from + * some slow/currently unavailable resource, such as an external I2C EEPconst), + * Then the class request handler responsible should call the USBDeferDataStage() + * macro. In this case, the firmware may wait up to 500ms, before it is required + * to transmit the first IN data packet. Once the data is ready, and the firmware + * is ready to begin sending the data, it should then call the + * USBCtrlEPAllowDataStage() function to start the data stage. + */ + if(USBDeferINDataStagePackets == false) + { + USBCtrlEPAllowDataStage(); + } + + // 2. (Optionally) allow the status stage now, to prepare for early termination. + // Note: If a class request handler decided to set USBDeferStatusStagePacket == true, + // then it is responsible for eventually calling USBCtrlEPAllowStatusStage() once it + // is ready. If the class request handler does this, it needs to be careful to + // be written so that it can handle the early termination scenario. + // Ex: It should call USBCtrlEPAllowStatusStage() when any of the following occurs: + // 1. The desired total number of bytes were sent to the host. + // 2. The number of bytes that the host originally requested (in the SETUP packet that + // started the control transfer) has been reached. + // 3. Or, if a timeout occurs (ex: <50ms since the last successful EP0 IN transaction), regardless + // of how many bytes have actually been sent. This is necessary to prevent a deadlock situation + // (where the control transfer can't complete, due to continuous NAK on status stage) if the + // host performs early termination. If enabled, the USB_ENABLE_STATUS_STAGE_TIMEOUTS usb_config.h + // option can take care of this for you. + // Note: For this type of control transfer, there is normally no harm in simply arming the + // status stage packet right now, even if the IN data is not ready yet. This allows for + // immediate early termination, without adding unnecessary delay. Therefore, it is generally not + // recommended for the USB class handler firmware to call USBDeferStatusStage(), for this + // type of control transfer. If the USB class handler firmware needs more time to fetch the IN + // data that needs to be sent to the host, it should instead use the USBDeferDataStage() function. + USBStatusStageEnabledFlag2 = false; + USBStatusStageEnabledFlag1 = false; + if(USBDeferStatusStagePacket == false) + { + USBCtrlEPAllowStatusStage(); + } + } + else // (SetupPkt.DataDir == USB_SETUP_DIRECTION_HOST_TO_DEVICE) + { + //This situation occurs for special types of control transfers, + //such as that which occurs when the host sends a SET_ADDRESS + //control transfer. Ex: + // + // | + + //Although the data direction is HOST_TO_DEVICE, there is no data stage + //(hence: outPipes[0].info.bits.busy == 0). There is however still + //an IN status stage. + + controlTransferState = CTRL_TRF_RX; //Since this is a HOST_TO_DEVICE control transfer + + //1. Prepare OUT EP to receive the next SETUP packet. + pBDTEntryEP0OutNext->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress(&SetupPkt); + pBDTEntryEP0OutNext->STAT.Val = _BSTALL; + pBDTEntryEP0OutNext->STAT.Val |= _USIE; + + //2. Prepare for IN status stage of the control transfer + USBStatusStageEnabledFlag2 = false; + USBStatusStageEnabledFlag1 = false; + if(USBDeferStatusStagePacket == false) + { + USBCtrlEPAllowStatusStage(); + } + } + + }//end if(ctrl_trf_session_owner == MUID_NULL) + +}//end USBCtrlEPServiceComplete + + +/****************************************************************************** + * Function: void USBCtrlTrfTxService(void) + * + * PreCondition: pSrc, wCount, and usb_stat.ctrl_trf_mem are setup properly. + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine is used for device to host control transfers + * (IN transactions). This function takes care of managing a + * transfer over multiple USB transactions. + * This routine should be called from only two places. + * One from USBCtrlEPServiceComplete() and one from + * USBCtrlTrfInHandler(). + * + * Note: + *****************************************************************************/ +static void USBCtrlTrfTxService(void) +{ + uint8_t byteToSend; + + //Figure out how many bytes of data to send in the next IN transaction. + //Assume a full size packet, unless otherwise determined below. + byteToSend = USB_EP0_BUFF_SIZE; + if(inPipes[0].wCount.Val < (uint8_t)USB_EP0_BUFF_SIZE) + { + byteToSend = inPipes[0].wCount.Val; + + //Keep track of whether or not we have sent a "short packet" yet. + //This is useful so that later on, we can configure EP0 IN to STALL, + //after we have sent all of the intended data. This makes sure the + //hardware STALLs if the host erroneously tries to send more IN token + //packets, requesting more data than intended in the control transfer. + if(shortPacketStatus == SHORT_PKT_NOT_USED) + { + shortPacketStatus = SHORT_PKT_PENDING; + } + else if(shortPacketStatus == SHORT_PKT_PENDING) + { + shortPacketStatus = SHORT_PKT_SENT; + } + } + + //Keep track of how many bytes remain to be sent in the transfer, by + //subtracting the number of bytes about to be sent from the total. + inPipes[0].wCount.Val -= byteToSend; + + //Next, load the number of bytes to send to BC7..0 in buffer descriptor. + //Note: Control endpoints may never have a max packet size of > 64 bytes. + //Therefore, the BC8 and BC9 bits should always be maintained clear. + pBDTEntryIn[0]->CNT = byteToSend; + + //Now copy the data from the source location, to the CtrlTrfData[] buffer, + //which we will send to the host. + pDst = (USB_VOLATILE uint8_t*)CtrlTrfData; // Set destination pointer + if(inPipes[0].info.bits.ctrl_trf_mem == USB_EP0_ROM) // Determine type of memory source + { + while(byteToSend) + { + *pDst++ = *inPipes[0].pSrc.bRom++; + byteToSend--; + }//end while(byte_to_send.Val) + } + else // RAM + { + while(byteToSend) + { + *pDst++ = *inPipes[0].pSrc.bRam++; + byteToSend--; + }//end while(byte_to_send.Val) + }//end if(usb_stat.ctrl_trf_mem == _const) +}//end USBCtrlTrfTxService + +/****************************************************************************** + * Function: void USBCtrlTrfRxService(void) + * + * PreCondition: pDst and wCount are setup properly. + * pSrc is always &CtrlTrfData + * usb_stat.ctrl_trf_mem is always USB_EP0_RAM. + * wCount should be set to 0 at the start of each control + * transfer. + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine is used for host to device control transfers + * (uses OUT transactions). This function receives the data that arrives + * on EP0 OUT, and copies it into the appropriate outPipes[0].pDst.bRam + * buffer. Once the host has sent all the data it was intending + * to send, this function will call the appropriate outPipes[0].pFunc() + * handler (unless it is NULL), so that it can be used by the + * intended target firmware. + * + * Note: None + *****************************************************************************/ +static void USBCtrlTrfRxService(void) +{ + uint8_t byteToRead; + uint8_t i; + + //Load byteToRead with the number of bytes the host just sent us in the + //last OUT transaction. + byteToRead = pBDTEntryEP0OutCurrent->CNT; + + //Update the "outPipes[0].wCount.Val", which keeps track of the total number + //of remaining bytes expected to be received from the host, in the control + //transfer. First check to see if the host sent us more bytes than the + //application firmware was expecting to receive. + if(byteToRead > outPipes[0].wCount.Val) + { + byteToRead = outPipes[0].wCount.Val; + } + //Reduce the number of remaining bytes by the number we just received. + outPipes[0].wCount.Val -= byteToRead; + + //Copy the OUT DATAx packet bytes that we just received from the host, + //into the user application buffer space. + for(i=0;i 0) + { + pBDTEntryEP0OutNext->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress(&CtrlTrfData); + if(pBDTEntryEP0OutCurrent->STAT.DTS == 0) + { + pBDTEntryEP0OutNext->STAT.Val = _DAT1|(_DTSEN & _DTS_CHECKING_ENABLED); + pBDTEntryEP0OutNext->STAT.Val |= _USIE; + } + else + { + pBDTEntryEP0OutNext->STAT.Val = _DAT0|(_DTSEN & _DTS_CHECKING_ENABLED); + pBDTEntryEP0OutNext->STAT.Val |= _USIE; + } + } + else + { + //We have received all OUT packets that we were expecting to + //receive for the control transfer. Prepare EP0 OUT to receive + //the next SETUP transaction that may arrive. + pBDTEntryEP0OutNext->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress(&SetupPkt); + //Configure EP0 OUT to receive the next SETUP transaction for any future + //control transfers. However, set BSTALL in case the host tries to send + //more data than it claims it was going to send. + pBDTEntryEP0OutNext->STAT.Val = _BSTALL; + pBDTEntryEP0OutNext->STAT.Val |= _USIE; + + //All data bytes for the host to device control write (OUT) have now been + //received successfully. + //Go ahead and call the user specified callback function, to use/consume + //the control transfer data (ex: if the "void (*function)" parameter + //was non-NULL when USBEP0Receive() was called). + if(outPipes[0].pFunc != NULL) + { + #if defined(__XC8) + //Special pragmas to suppress an expected/harmless warning + //message when building with the XC8 compiler + #pragma warning push + #pragma warning disable 1088 + outPipes[0].pFunc(); //Call the user's callback function + #pragma warning pop + #else + outPipes[0].pFunc(); //Call the user's callback function + #endif + } + outPipes[0].info.bits.busy = 0; + + //Ready to arm status stage IN transaction now, if the application + //firmware has completed processing the request. If it is still busy + //and needs more time to finish handling the request, then the user + //callback (the one called by the outPipes[0].pFunc();) should set the + //USBDeferStatusStagePacket to true (by calling USBDeferStatusStage()). In + //this case, it is the application's firmware responsibility to call + //the USBCtrlEPAllowStatusStage() function, once it is fully done handling the request. + //Note: The application firmware must process the request and call + //USBCtrlEPAllowStatusStage() in a semi-timely fashion. "Semi-timely" + //means either 50ms, 500ms, or 5 seconds, depending on the type of + //control transfer. See the USB 2.0 specification section 9.2.6 for + //more details. + if(USBDeferStatusStagePacket == false) + { + USBCtrlEPAllowStatusStage(); + } + } + +}//end USBCtrlTrfRxService + + +/******************************************************************** + * Function: void USBStdSetCfgHandler(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine first disables all endpoints by + * clearing UEP registers. It then configures + * (initializes) endpoints by calling the callback + * function USBCBInitEP(). + * + * Note: None + *******************************************************************/ +static void USBStdSetCfgHandler(void) +{ + uint8_t i; + + // This will generate a zero length packet + inPipes[0].info.bits.busy = 1; + + //Clear all of the endpoint control registers + DisableNonZeroEndpoints(USB_MAX_EP_NUMBER); + + //Clear all of the BDT entries + memset((void*)&BDT[0], 0x00, sizeof(BDT)); + + // Assert reset request to all of the Ping Pong buffer pointers + USBPingPongBufferReset = 1; + + //Re-Initialize all ping pong software state bits to 0 (which corresponds to + //the EVEN buffer being the next one that will be used), since we are also + //doing a hardware ping pong pointer reset above. + for(i = 0; i < (uint8_t)(USB_MAX_EP_NUMBER+1u); i++) + { + ep_data_in[i].Val = 0u; + ep_data_out[i].Val = 0u; + } + + //clear the alternate interface settings + memset((void*)&USBAlternateInterface,0x00,USB_MAX_NUM_INT); + + //Stop trying to reset ping pong buffer pointers + USBPingPongBufferReset = 0; + + pBDTEntryIn[0] = (volatile BDT_ENTRY*)&BDT[EP0_IN_EVEN]; + + //Set the next out to the current out packet + pBDTEntryEP0OutCurrent = (volatile BDT_ENTRY*)&BDT[EP0_OUT_EVEN]; + pBDTEntryEP0OutNext = pBDTEntryEP0OutCurrent; + + //set the current configuration + USBActiveConfiguration = SetupPkt.bConfigurationValue; + + //if the configuration value == 0 + if(USBActiveConfiguration == 0) + { + //Go back to the addressed state + USBDeviceState = ADDRESS_STATE; + } + else + { + //initialize the required endpoints + USB_SET_CONFIGURATION_HANDLER(EVENT_CONFIGURED,(void*)&USBActiveConfiguration,1); + + //Otherwise go to the configured state. Update the state variable last, + //after performing all of the set configuration related initialization + //tasks. + USBDeviceState = CONFIGURED_STATE; + }//end if(SetupPkt.bConfigurationValue == 0) +}//end USBStdSetCfgHandler + + +/******************************************************************** + * Function: void USBStdGetDscHandler(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine handles the standard GET_DESCRIPTOR + * request. + * + * Note: None + *******************************************************************/ +static void USBStdGetDscHandler(void) +{ + if(SetupPkt.bmRequestType == 0x80) + { + inPipes[0].info.Val = USB_EP0_ROM | USB_EP0_BUSY | USB_EP0_INCLUDE_ZERO; + + switch(SetupPkt.bDescriptorType) + { + case USB_DESCRIPTOR_DEVICE: + #if !defined(USB_USER_DEVICE_DESCRIPTOR) + inPipes[0].pSrc.bRom = (const uint8_t*)&device_dsc; + #else + inPipes[0].pSrc.bRom = (const uint8_t*)USB_USER_DEVICE_DESCRIPTOR; + #endif + inPipes[0].wCount.Val = sizeof(device_dsc); + break; + case USB_DESCRIPTOR_CONFIGURATION: + //First perform error case check, to make sure the host is requesting a + //legal descriptor index. If the request index is illegal, don't do + //anything (so that the default STALL response will be sent). + if(SetupPkt.bDscIndex < USB_MAX_NUM_CONFIG_DSC) + { + #if !defined(USB_USER_CONFIG_DESCRIPTOR) + inPipes[0].pSrc.bRom = *(USB_CD_Ptr+SetupPkt.bDscIndex); + #else + inPipes[0].pSrc.bRom = *(USB_USER_CONFIG_DESCRIPTOR+SetupPkt.bDscIndex); + #endif + + //This must be loaded using byte addressing. The source pointer + // may not be word aligned for the 16 or 32 bit machines resulting + // in an address error on the dereference. + inPipes[0].wCount.byte.LB = *(inPipes[0].pSrc.bRom+2); + inPipes[0].wCount.byte.HB = *(inPipes[0].pSrc.bRom+3); + } + else + { + inPipes[0].info.Val = 0; + } + break; + case USB_DESCRIPTOR_STRING: + //USB_NUM_STRING_DESCRIPTORS was introduced as optional in release v2.3. In v2.4 and + // later it is now mandatory. This should be defined in usb_config.h and should + // indicate the number of string descriptors. + if(SetupPkt.bDscIndexSTAT.UOWN == 1) && (p->STAT.BSTALL == 1)) + CtrlTrfData[0]=0x01; // Set bit0 + break; + } + }//end switch + + if(inPipes[0].info.bits.busy == 1) + { + inPipes[0].pSrc.bRam = (uint8_t*)&CtrlTrfData; // Set Source + inPipes[0].info.bits.ctrl_trf_mem = USB_EP0_RAM; // Set memory type + inPipes[0].wCount.v[0] = 2; // Set data count + }//end if(...) +}//end USBStdGetStatusHandler + +/******************************************************************** + * Function: void USBStallHandler(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: + * + * Overview: This function handles the event of a STALL + * occurring on the bus + * + * Note: None + *******************************************************************/ +static void USBStallHandler(void) +{ + /* + * Does not really have to do anything here, + * even for the control endpoint. + * All BDs of Endpoint 0 are owned by SIE right now, + * but once a Setup Transaction is received, the ownership + * for EP0_OUT will be returned to CPU. + * When the Setup Transaction is serviced, the ownership + * for EP0_IN will then be forced back to CPU by firmware. + */ + + if(U1EP0bits.EPSTALL == 1) + { + // UOWN - if 0, owned by CPU, if 1, owned by SIE + if((pBDTEntryEP0OutCurrent->STAT.Val == _USIE) && (pBDTEntryIn[0]->STAT.Val == (_USIE|_BSTALL))) + { + // Set ep0Bo to stall also + pBDTEntryEP0OutCurrent->STAT.Val = _DAT0|(_DTSEN & _DTS_CHECKING_ENABLED)|_BSTALL; + pBDTEntryEP0OutCurrent->STAT.Val |= _USIE; + }//end if + U1EP0bits.EPSTALL = 0; // Clear stall status + }//end if + + USBClearInterruptFlag(USBStallIFReg,USBStallIFBitNum); +} + +/******************************************************************** + * Function: void USBSuspend(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: + * + * Overview: This function handles if the host tries to + * suspend the device + * + * Note: None + *******************************************************************/ +static void USBSuspend(void) +{ + /* + * NOTE: Do not clear UIRbits.ACTVIF here! + * Reason: + * ACTVIF is only generated once an IDLEIF has been generated. + * This is a 1:1 ratio interrupt generation. + * For every IDLEIF, there will be only one ACTVIF regardless of + * the number of subsequent bus transitions. + * + * If the ACTIF is cleared here, a problem could occur when: + * [ IDLE ][bus activity -> + * <--- 3 ms -----> ^ + * ^ ACTVIF=1 + * IDLEIF=1 + * # # # # (#=Program polling flags) + * ^ + * This polling loop will see both + * IDLEIF=1 and ACTVIF=1. + * However, the program services IDLEIF first + * because ACTIVIE=0. + * If this routine clears the only ACTIVIF, + * then it can never get out of the suspend + * mode. + */ + USBActivityIE = 1; // Enable bus activity interrupt + USBClearInterruptFlag(USBIdleIFReg,USBIdleIFBitNum); + + #if defined(__18CXX) || defined(_PIC14E) || defined(__XC8) + U1CONbits.SUSPND = 1; // Put USB module in power conserve + // mode, SIE clock inactive + #endif + USBBusIsSuspended = true; + USBTicksSinceSuspendEnd = 0; + + /* + * At this point the PIC can go into sleep,idle, or + * switch to a slower clock, etc. This should be done in the + * USBCBSuspend() if necessary. + */ + USB_SUSPEND_HANDLER(EVENT_SUSPEND,0,0); +} + +/******************************************************************** + * Function: void USBWakeFromSuspend(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: + * + * Note: None + *******************************************************************/ +static void USBWakeFromSuspend(void) +{ + USBBusIsSuspended = false; + + /* + * If using clock switching, the place to restore the original + * microcontroller core clock frequency is in the USBCBWakeFromSuspend() callback + */ + USB_WAKEUP_FROM_SUSPEND_HANDLER(EVENT_RESUME,0,0); + + #if defined(__18CXX) || defined(_PIC14E) || defined(__XC8) + //To avoid improperly clocking the USB module, make sure the oscillator + //settings are consistent with USB operation before clearing the SUSPND bit. + //Make sure the correct oscillator settings are selected in the + //"USB_WAKEUP_FROM_SUSPEND_HANDLER(EVENT_RESUME,0,0)" handler. + U1CONbits.SUSPND = 0; // Bring USB module out of power conserve + // mode. + #endif + + + USBActivityIE = 0; + + /******************************************************************** + Bug Fix: Feb 26, 2007 v2.1 + ********************************************************************* + The ACTVIF bit cannot be cleared immediately after the USB module wakes + up from Suspend or while the USB module is suspended. A few clock cycles + are required to synchronize the internal hardware state machine before + the ACTIVIF bit can be cleared by firmware. Clearing the ACTVIF bit + before the internal hardware is synchronized may not have an effect on + the value of ACTVIF. Additionally, if the USB module uses the clock from + the 96 MHz PLL source, then after clearing the SUSPND bit, the USB + module may not be immediately operational while waiting for the 96 MHz + PLL to lock. + ********************************************************************/ + + // UIRbits.ACTVIF = 0; // Removed + #if defined(__18CXX) || defined(__XC8) + while(USBActivityIF) + #endif + { + USBClearInterruptFlag(USBActivityIFReg,USBActivityIFBitNum); + } // Added + + USBTicksSinceSuspendEnd = 0; + +}//end USBWakeFromSuspend + +/******************************************************************** + * Function: void USBCtrlEPService(void) + * + * PreCondition: USTAT is loaded with a valid endpoint address. + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: USBCtrlEPService checks for three transaction + * types that it knows how to service and services + * them: + * 1. EP0 SETUP + * 2. EP0 OUT + * 3. EP0 IN + * It ignores all other types (i.e. EP1, EP2, etc.) + * + * Note: None + *******************************************************************/ +static void USBCtrlEPService(void) +{ + //If we get to here, that means a successful transaction has just occurred + //on EP0. This means "progress" has occurred in the currently pending + //control transfer, so we should re-initialize our timeout counter. + #if defined(USB_ENABLE_STATUS_STAGE_TIMEOUTS) + USBStatusStageTimeoutCounter = USB_STATUS_STAGE_TIMEOUT; + #endif + + //Check if the last transaction was on EP0 OUT endpoint (of any kind, to either the even or odd buffer if ping pong buffers used) + if((USTATcopy.Val & USTAT_EP0_PP_MASK) == USTAT_EP0_OUT_EVEN) + { + //Point to the EP0 OUT buffer of the buffer that arrived + #if defined (_PIC14E) || defined(__18CXX) || defined(__XC8) + pBDTEntryEP0OutCurrent = (volatile BDT_ENTRY*)&BDT[(USTATcopy.Val & USTAT_EP_MASK)>>1]; + #elif defined(__C30__) || defined(__C32__) || defined __XC16__ + pBDTEntryEP0OutCurrent = (volatile BDT_ENTRY*)&BDT[(USTATcopy.Val & USTAT_EP_MASK)>>2]; + #else + #error "unimplemented" + #endif + + //Set the next out to the current out packet + pBDTEntryEP0OutNext = pBDTEntryEP0OutCurrent; + //Toggle it to the next ping pong buffer (if applicable) + pBDTEntryEP0OutNext = (volatile BDT_ENTRY*)(((uintptr_t)pBDTEntryEP0OutNext) ^ USB_NEXT_EP0_OUT_PING_PONG); + + //If the current EP0 OUT buffer has a SETUP packet + if(pBDTEntryEP0OutCurrent->STAT.PID == PID_SETUP) + { + //The SETUP transaction data may have gone into the the CtrlTrfData + //buffer, or elsewhere, depending upon how the BDT was prepared + //before the transaction. Therefore, we should copy the data to the + //SetupPkt buffer so it can be processed correctly by USBCtrlTrfSetupHandler(). + memcpy((uint8_t*)&SetupPkt, (uint8_t*)ConvertToVirtualAddress(pBDTEntryEP0OutCurrent->ADR), 8); + + //Handle the control transfer (parse the 8-byte SETUP command and figure out what to do) + USBCtrlTrfSetupHandler(); + } + else + { + //Handle the DATA transfer + USBCtrlTrfOutHandler(); + } + } + else if((USTATcopy.Val & USTAT_EP0_PP_MASK) == USTAT_EP0_IN) + { + //Otherwise the transmission was and EP0 IN + // so take care of the IN transfer + USBCtrlTrfInHandler(); + } + +}//end USBCtrlEPService + +/******************************************************************** + * Function: void USBCtrlTrfSetupHandler(void) + * + * PreCondition: SetupPkt buffer is loaded with valid USB Setup Data + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine is a task dispatcher and has 3 stages. + * 1. It initializes the control transfer state machine. + * 2. It calls on each of the module that may know how to + * service the Setup Request from the host. + * Module Example: USBD, HID, CDC, MSD, ... + * A callback function, USBCBCheckOtherReq(), + * is required to call other module handlers. + * 3. Once each of the modules has had a chance to check if + * it is responsible for servicing the request, stage 3 + * then checks direction of the transfer to determine how + * to prepare EP0 for the control transfer. + * Refer to USBCtrlEPServiceComplete() for more details. + * + * Note: Microchip USB Firmware has three different states for + * the control transfer state machine: + * 1. WAIT_SETUP + * 2. CTRL_TRF_TX (device sends data to host through IN transactions) + * 3. CTRL_TRF_RX (device receives data from host through OUT transactions) + * Refer to firmware manual to find out how one state + * is transitioned to another. + * + * A Control Transfer is composed of many USB transactions. + * When transferring data over multiple transactions, + * it is important to keep track of data source, data + * destination, and data count. These three parameters are + * stored in pSrc,pDst, and wCount. A flag is used to + * note if the data source is from const or RAM. + * + *******************************************************************/ +static void USBCtrlTrfSetupHandler(void) +{ + //-------------------------------------------------------------------------- + //1. Re-initialize state tracking variables related to control transfers. + //-------------------------------------------------------------------------- + shortPacketStatus = SHORT_PKT_NOT_USED; + USBDeferStatusStagePacket = false; + USBDeferINDataStagePackets = false; + USBDeferOUTDataStagePackets = false; + BothEP0OutUOWNsSet = false; + controlTransferState = WAIT_SETUP; + + //Abandon any previous control transfers that might have been using EP0. + //Ordinarily, nothing actually needs abandoning, since the previous control + //transfer would have completed successfully prior to the host sending the next + //SETUP packet. However, in a timeout error case, or after an EP0 STALL event, + //one or more UOWN bits might still be set. If so, we should clear the UOWN bits, + //so the EP0 IN/OUT endpoints are in a known inactive state, ready for re-arming + //by the class request handler that will be called next. + pBDTEntryIn[0]->STAT.Val &= ~(_USIE); + + pBDTEntryIn[0] = (volatile BDT_ENTRY*)(((uintptr_t)pBDTEntryIn[0]) ^ USB_NEXT_EP0_IN_PING_PONG); + pBDTEntryIn[0]->STAT.Val &= ~(_USIE); + pBDTEntryIn[0] = (volatile BDT_ENTRY*)(((uintptr_t)pBDTEntryIn[0]) ^ USB_NEXT_EP0_IN_PING_PONG); + pBDTEntryEP0OutNext->STAT.Val &= ~(_USIE); + + inPipes[0].info.Val = 0; + inPipes[0].wCount.Val = 0; + outPipes[0].info.Val = 0; + outPipes[0].wCount.Val = 0; + + + //-------------------------------------------------------------------------- + //2. Now find out what was in the SETUP packet, and begin handling the request. + //-------------------------------------------------------------------------- + USBCheckStdRequest(); //Check for standard USB "Chapter 9" requests. + USB_NONSTANDARD_EP0_REQUEST_HANDLER(EVENT_EP0_REQUEST,0,0); //Check for USB device class specific requests + + + //-------------------------------------------------------------------------- + //3. Re-arm EP0 IN and EP0 OUT endpoints, based on the control transfer in + // progress. If one of the above handlers (in step 2) knew how to process + // the request, it will have set one of the inPipes[0].info.bits.busy or + // outPipes[0].info.bits.busy flags = 1. This lets the + // USBCtrlEPServiceComplete() function know how and which endpoints to + // arm. If both info.bits.busy flags are = 0, then no one knew how to + // process the request. In this case, the default behavior will be to + // perform protocol STALL on EP0. + //-------------------------------------------------------------------------- + USBCtrlEPServiceComplete(); +}//end USBCtrlTrfSetupHandler + + +/****************************************************************************** + * Function: void USBCtrlTrfOutHandler(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine handles an OUT transaction according to + * which control transfer state is currently active. + * + * Note: Note that if the the control transfer was from + * host to device, the session owner should be notified + * at the end of each OUT transaction to service the + * received data. + * + *****************************************************************************/ +static void USBCtrlTrfOutHandler(void) +{ + if(controlTransferState == CTRL_TRF_RX) + { + USBCtrlTrfRxService(); //Copies the newly received data into the appropriate buffer and configures EP0 OUT for next transaction. + } + else //In this case the last OUT transaction must have been a status stage of a CTRL_TRF_TX (... <-- this last OUT just occurred as the status stage) + { + //If the status stage is complete, this means we are done with the + //control transfer. Go back to the idle "WAIT_SETUP" state. + controlTransferState = WAIT_SETUP; + + //Prepare EP0 OUT for the next SETUP transaction, however, it may have + //already been prepared if ping-pong buffering was enabled on EP0 OUT, + //and the last control transfer was of direction: device to host, see + //USBCtrlEPServiceComplete(). If it was already prepared, do not want + //to do anything to the BDT. + if(BothEP0OutUOWNsSet == false) + { + pBDTEntryEP0OutNext->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress(&SetupPkt); + pBDTEntryEP0OutNext->STAT.Val = _DAT0|(_DTSEN & _DTS_CHECKING_ENABLED)|_BSTALL; + pBDTEntryEP0OutNext->STAT.Val |= _USIE; + } + else + { + BothEP0OutUOWNsSet = false; + } + } +} + +/****************************************************************************** + * Function: void USBCtrlTrfInHandler(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine handles an IN transaction according to + * which control transfer state is currently active. + * + * Note: A Set Address Request must not change the actual address + * of the device until the completion of the control + * transfer. The end of the control transfer for Set Address + * Request is an IN transaction. Therefore it is necessary + * to service this unique situation when the condition is + * right. Macro mUSBCheckAdrPendingState is defined in + * usb9.h and its function is to specifically service this + * event. + *****************************************************************************/ +static void USBCtrlTrfInHandler(void) +{ + uint8_t lastDTS; + + lastDTS = pBDTEntryIn[0]->STAT.DTS; + + //switch to the next ping pong buffer + pBDTEntryIn[0] = (volatile BDT_ENTRY*)(((uintptr_t)pBDTEntryIn[0]) ^ USB_NEXT_EP0_IN_PING_PONG); + + //Must check if in ADR_PENDING_STATE. If so, we need to update the address + //now, since the IN status stage of the (set address) control transfer has + //evidently completed successfully. + if(USBDeviceState == ADR_PENDING_STATE) + { + U1ADDR = (SetupPkt.bDevADR & 0x7F); + if(U1ADDR != 0u) + { + USBDeviceState=ADDRESS_STATE; + } + else + { + USBDeviceState=DEFAULT_STATE; + } + }//end if + + + if(controlTransferState == CTRL_TRF_TX) + { + pBDTEntryIn[0]->ADR = ConvertToPhysicalAddress(CtrlTrfData); + USBCtrlTrfTxService(); + + //Check if we have already sent a short packet. If so, configure + //the endpoint to STALL in response to any further IN tokens (in the + //case that the host erroneously tries to receive more data than it + //should). + if(shortPacketStatus == SHORT_PKT_SENT) + { + // If a short packet has been sent, don't want to send any more, + // stall next time if host is still trying to read. + pBDTEntryIn[0]->STAT.Val = _BSTALL; + pBDTEntryIn[0]->STAT.Val |= _USIE; + } + else + { + if(lastDTS == 0) + { + pBDTEntryIn[0]->STAT.Val = _DAT1|(_DTSEN & _DTS_CHECKING_ENABLED); + pBDTEntryIn[0]->STAT.Val |= _USIE; + } + else + { + pBDTEntryIn[0]->STAT.Val = _DAT0|(_DTSEN & _DTS_CHECKING_ENABLED); + pBDTEntryIn[0]->STAT.Val |= _USIE; + } + }//end if(...)else + } + else // must have been a CTRL_TRF_RX status stage IN packet (... <-- this last IN just occurred as the status stage) + { + //if someone is still expecting data from the control transfer + // then make sure to terminate that request and let them know that + // they are done + if(outPipes[0].info.bits.busy == 1) + { + if(outPipes[0].pFunc != NULL) + { + outPipes[0].pFunc(); + } + outPipes[0].info.bits.busy = 0; + } + + controlTransferState = WAIT_SETUP; + //Don't need to arm EP0 OUT here. It was already armed by the last that + //got processed by the USBCtrlTrfRxService() handler. + } + +} + + +/******************************************************************** + * Function: void USBCheckStdRequest(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine checks the setup data packet to see + * if it knows how to handle it + * + * Note: None + *******************************************************************/ +static void USBCheckStdRequest(void) +{ + if(SetupPkt.RequestType != USB_SETUP_TYPE_STANDARD_BITFIELD) return; + + switch(SetupPkt.bRequest) + { + case USB_REQUEST_SET_ADDRESS: + inPipes[0].info.bits.busy = 1; // This will generate a zero length packet + USBDeviceState = ADR_PENDING_STATE; // Update state only + /* See USBCtrlTrfInHandler() for the next step */ + break; + case USB_REQUEST_GET_DESCRIPTOR: + USBStdGetDscHandler(); + break; + case USB_REQUEST_SET_CONFIGURATION: + USBStdSetCfgHandler(); + break; + case USB_REQUEST_GET_CONFIGURATION: + inPipes[0].pSrc.bRam = (uint8_t*)&USBActiveConfiguration; // Set Source + inPipes[0].info.bits.ctrl_trf_mem = USB_EP0_RAM; // Set memory type + inPipes[0].wCount.v[0] = 1; // Set data count + inPipes[0].info.bits.busy = 1; + break; + case USB_REQUEST_GET_STATUS: + USBStdGetStatusHandler(); + break; + case USB_REQUEST_CLEAR_FEATURE: + case USB_REQUEST_SET_FEATURE: + USBStdFeatureReqHandler(); + break; + case USB_REQUEST_GET_INTERFACE: + inPipes[0].pSrc.bRam = (uint8_t*)&USBAlternateInterface[SetupPkt.bIntfID]; // Set source + inPipes[0].info.bits.ctrl_trf_mem = USB_EP0_RAM; // Set memory type + inPipes[0].wCount.v[0] = 1; // Set data count + inPipes[0].info.bits.busy = 1; + break; + case USB_REQUEST_SET_INTERFACE: + inPipes[0].info.bits.busy = 1; + USBAlternateInterface[SetupPkt.bIntfID] = SetupPkt.bAltID; + break; + case USB_REQUEST_SET_DESCRIPTOR: + USB_SET_DESCRIPTOR_HANDLER(EVENT_SET_DESCRIPTOR,0,0); + break; + case USB_REQUEST_SYNCH_FRAME: + default: + break; + }//end switch +}//end USBCheckStdRequest + +/******************************************************************** + * Function: void USBStdFeatureReqHandler(void) + * + * PreCondition: None + * + * Input: None + * + * Output: Can alter BDT entries. Can also modify USB stack + * Maintained variables. + * + * Side Effects: None + * + * Overview: This routine handles the standard SET & CLEAR + * FEATURES requests + * + * Note: This is a private function, intended for internal + * use by the USB stack, when processing SET/CLEAR + * feature requests. + *******************************************************************/ +static void USBStdFeatureReqHandler(void) +{ + BDT_ENTRY *p; + EP_STATUS current_ep_data; + #if defined(__C32__) + uint32_t* pUEP; + #else + unsigned char* pUEP; + #endif + + + #ifdef USB_SUPPORT_OTG + //Check for USB On-The-Go (OTG) specific requests + if ((SetupPkt.bFeature == OTG_FEATURE_B_HNP_ENABLE)&& + (SetupPkt.Recipient == USB_SETUP_RECIPIENT_DEVICE_BITFIELD)) + { + inPipes[0].info.bits.busy = 1; + if(SetupPkt.bRequest == USB_REQUEST_SET_FEATURE) + USBOTGEnableHnp(); + else + USBOTGDisableHnp(); + } + + if ((SetupPkt.bFeature == OTG_FEATURE_A_HNP_SUPPORT)&& + (SetupPkt.Recipient == USB_SETUP_RECIPIENT_DEVICE_BITFIELD)) + { + inPipes[0].info.bits.busy = 1; + if(SetupPkt.bRequest == USB_REQUEST_SET_FEATURE) + USBOTGEnableSupportHnp(); + else + USBOTGDisableSupportHnp(); + } + + if ((SetupPkt.bFeature == OTG_FEATURE_A_ALT_HNP_SUPPORT)&& + (SetupPkt.Recipient == USB_SETUP_RECIPIENT_DEVICE_BITFIELD)) + { + inPipes[0].info.bits.busy = 1; + if(SetupPkt.bRequest == USB_REQUEST_SET_FEATURE) + USBOTGEnableAltHnp(); + else + USBOTGDisableAltHnp(); + } + #endif //#ifdef USB_SUPPORT_OTG + + //Check if the host sent a valid SET or CLEAR feature (remote wakeup) request. + if((SetupPkt.bFeature == USB_FEATURE_DEVICE_REMOTE_WAKEUP)&& + (SetupPkt.Recipient == USB_SETUP_RECIPIENT_DEVICE_BITFIELD)) + { + inPipes[0].info.bits.busy = 1; + if(SetupPkt.bRequest == USB_REQUEST_SET_FEATURE) + RemoteWakeup = true; + else + RemoteWakeup = false; + }//end if + + //Check if the host sent a valid SET or CLEAR endpoint halt request. + if((SetupPkt.bFeature == USB_FEATURE_ENDPOINT_HALT)&& + (SetupPkt.Recipient == USB_SETUP_RECIPIENT_ENDPOINT_BITFIELD)&& + (SetupPkt.EPNum != 0) && (SetupPkt.EPNum <= USB_MAX_EP_NUMBER)&& + (USBDeviceState == CONFIGURED_STATE)) + { + //The request was valid. Take control of the control transfer and + //perform the host requested action. + inPipes[0].info.bits.busy = 1; + + //Fetch a pointer to the BDT that the host wants to SET/CLEAR halt on. + if(SetupPkt.EPDir == OUT_FROM_HOST) + { + p = (BDT_ENTRY*)pBDTEntryOut[SetupPkt.EPNum]; + current_ep_data.Val = ep_data_out[SetupPkt.EPNum].Val; + } + else + { + p = (BDT_ENTRY*)pBDTEntryIn[SetupPkt.EPNum]; + current_ep_data.Val = ep_data_in[SetupPkt.EPNum].Val; + } + + //If ping pong buffering is enabled on the requested endpoint, need + //to point to the one that is the active BDT entry which the SIE will + //use for the next attempted transaction on that EP number. + #if (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0) || (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG) + if(current_ep_data.bits.ping_pong_state == 0) //Check if even + { + p = (BDT_ENTRY*)(((uintptr_t)p) & (~USB_NEXT_PING_PONG)); + } + else //else must have been odd + { + p = (BDT_ENTRY*)(((uintptr_t)p) | USB_NEXT_PING_PONG); + } + #endif + + //Update the BDT pointers with the new, next entry based on the feature + // request + if(SetupPkt.EPDir == OUT_FROM_HOST) + { + pBDTEntryOut[SetupPkt.EPNum] = (volatile BDT_ENTRY *)p; + } + else + { + pBDTEntryIn[SetupPkt.EPNum] = (volatile BDT_ENTRY *)p; + } + + //Check if it was a SET_FEATURE endpoint halt request + if(SetupPkt.bRequest == USB_REQUEST_SET_FEATURE) + { + if(p->STAT.UOWN == 1) + { + //Mark that we are terminating this transfer and that the user + // needs to be notified later + if(SetupPkt.EPDir == OUT_FROM_HOST) + { + ep_data_out[SetupPkt.EPNum].bits.transfer_terminated = 1; + } + else + { + ep_data_in[SetupPkt.EPNum].bits.transfer_terminated = 1; + } + } + + //Then STALL the endpoint + p->STAT.Val |= _BSTALL; + p->STAT.Val |= _USIE; + }//if(SetupPkt.bRequest == USB_REQUEST_SET_FEATURE) + else + { + //Else the request must have been a CLEAR_FEATURE endpoint halt. + #if (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0) || (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG) + //toggle over the to the non-active BDT + p = (BDT_ENTRY*)(((uintptr_t)p) ^ USB_NEXT_PING_PONG); + + if(p->STAT.UOWN == 1) + { + //Clear UOWN and set DTS state so it will be correct the next time + //the application firmware uses USBTransferOnePacket() on the EP. + p->STAT.Val &= (~_USIE); //Clear UOWN bit + p->STAT.Val |= _DAT1; //Set DTS to DATA1 + USB_TRANSFER_TERMINATED_HANDLER(EVENT_TRANSFER_TERMINATED,p,sizeof(p)); + } + else + { + //UOWN already clear, but still need to set DTS to DATA1 + p->STAT.Val |= _DAT1; + } + + //toggle back to the active BDT (the one the SIE is currently looking at + //and will use for the next successful transaction to take place on the EP + p = (BDT_ENTRY*)(((uintptr_t)p) ^ USB_NEXT_PING_PONG); + + //Check if we are currently terminating, or have previously terminated + //a transaction on the given endpoint. If so, need to clear UOWN, + //set DTS to the proper state, and call the application callback + //function. + if((current_ep_data.bits.transfer_terminated != 0) || (p->STAT.UOWN == 1)) + { + if(SetupPkt.EPDir == OUT_FROM_HOST) + { + ep_data_out[SetupPkt.EPNum].bits.transfer_terminated = 0; + } + else + { + ep_data_in[SetupPkt.EPNum].bits.transfer_terminated = 0; + } + //clear UOWN, clear DTS to DATA0, and finally remove the STALL condition + p->STAT.Val &= ~(_USIE | _DAT1 | _BSTALL); + //Call the application event handler callback function, so it can + //decide if the endpoint should get re-armed again or not. + USB_TRANSFER_TERMINATED_HANDLER(EVENT_TRANSFER_TERMINATED,p,sizeof(p)); + } + else + { + //clear UOWN, clear DTS to DATA0, and finally remove the STALL condition + p->STAT.Val &= ~(_USIE | _DAT1 | _BSTALL); + } + #else //else we must not be using ping-pong buffering on the requested endpoint + //Check if we need to call the user transfer terminated event callback function. + //We should call the callback, if the endpoint was previously terminated, + //or the endpoint is currently armed, and the host is performing clear + //endpoint halt, even though the endpoint wasn't stalled. + if((current_ep_data.bits.transfer_terminated != 0) || (p->STAT.UOWN == 1)) + { + //We are going to call the user transfer terminated callback. + //Clear the flag so we know we took care of it and don't need + //to call it again later. + if(SetupPkt.EPDir == OUT_FROM_HOST) + { + ep_data_out[SetupPkt.EPNum].bits.transfer_terminated = 0; + } + else + { + ep_data_in[SetupPkt.EPNum].bits.transfer_terminated = 0; + } + + //Clear UOWN and remove the STALL condition. + // In this case we also need to set the DTS bit to 1 so that + // it toggles to DATA0 the next time the application firmware + // calls USBTransferOnePacket() (or equivalent macro). + p->STAT.Val &= ~(_USIE | _BSTALL); + p->STAT.Val |= _DAT1; + //Let the application firmware know a transaction just + //got terminated by the host, and that it is now free to + //re-arm the endpoint or do other tasks if desired. + USB_TRANSFER_TERMINATED_HANDLER(EVENT_TRANSFER_TERMINATED,p,sizeof(p)); + } + else + { + //Clear UOWN and remove the STALL condition. + // In this case we also need to set the DTS bit to 1 so that + // it toggles to DATA0 the next time the application firmware + // calls USBTransferOnePacket() (or equivalent macro). + p->STAT.Val &= ~(_USIE | _BSTALL); + p->STAT.Val |= _DAT1; + } + #endif //end of #if (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0) || (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG) + + //Get a pointer to the appropriate UEPn register + #if defined(__C32__) + pUEP = (uint32_t*)(&U1EP0); + pUEP += (SetupPkt.EPNum*4); + #else + pUEP = (unsigned char*)(&U1EP0+SetupPkt.EPNum); + #endif + + //Clear the STALL bit in the UEP register + *pUEP &= ~UEP_STALL; + }//end if(SetupPkt.bRequest == USB_REQUEST_SET_FEATURE) + }//end if (lots of checks for set/clear endpoint halt) +}//end USBStdFeatureReqHandler + + + + +/************************************************************************** + Function: + void USBIncrement1msInternalTimers(void) + + Description: + This function increments internal 1ms time base counters, which are + useful for application code (that can use a 1ms time base/counter), and + for certain USB event timing specific purposes. + + In USB full speed applications, the application code does not need to (and should + not) explicitly call this function, as the USBDeviceTasks() function will + automatically call this function whenever a 1ms time interval has elapsed + (assuming the code is calling USBDeviceTasks() frequently enough in USB_POLLING + mode, or that USB interrupts aren't being masked for more than 1ms at a time + in USB_INTERRUPT mode). + + In USB low speed applications, the application firmware is responsible for + periodically calling this function at a ~1ms rate. This can be done using + a general purpose microcontroller timer set to interrupt every 1ms for example. + If the low speed application code does not call this function, the internal timers + will not increment, and the USBGet1msTickCount() API function will not be available. + Additionally, certain USB stack operations (like control transfer timeouts) + may be unavailable. + + Precondition: + This function should be called only after USBDeviceInit() has been + called (at least once at the start of the application). Ordinarily, + application code should never call this function, unless it is a low speed + USB device. + + Parameters: + None + + Return Values: + None + + Remarks: + This function does not need to be called during USB suspend conditions, when + the USB module/stack is disabled, or when the USB cable is detached from the host. + ***************************************************************************/ +void USBIncrement1msInternalTimers(void) +{ + #if(USB_SPEED_OPTION == USB_LOW_SPEED) + #warning "For low speed USB applications, read the function comments for the USBIncrement1msInternalTimers() function, and implement code to call this function periodically." + #endif + + //Increment timekeeping 1ms tick counters. Useful for other APIs/code + //that needs a 1ms time base that is active during USB non-suspended operation. + USB1msTickCount++; + if(USBIsBusSuspended() == false) + { + USBTicksSinceSuspendEnd++; + //Check for 8-bit wraparound. If so, force it to saturate at 255. + if(USBTicksSinceSuspendEnd == 0) + { + USBTicksSinceSuspendEnd = 255; + } + } +} + + + + +/************************************************************************** + Function: + uint32_t USBGet1msTickCount(void) + + Description: + This function retrieves a 32-bit unsigned integer that normally increments by + one every one millisecond. The count value starts from zero when the + USBDeviceInit() function is first called. See the remarks section for + details on special circumstances where the tick count will not increment. + + Precondition: + This function should be called only after USBDeviceInit() has been + called (at least once at the start of the application). + + Parameters: + None + + Return Values: + uint32_t representing the approximate millisecond count, since the time the + USBDeviceInit() function was first called. + + Remarks: + On 8-bit USB full speed devices, the internal counter is incremented on + every SOF packet detected. Therefore, it will not increment during suspend + or when the USB cable is detached. However, on 16-bit devices, the T1MSECIF + hardware interrupt source is used to increment the internal counter. Therefore, + on 16-bit devices, the count continue to increment during USB suspend or + detach events, so long as the application code has not put the microcontroller + to sleep during these events, and the application firmware is regularly + calling the USBDeviceTasks() function (or allowing it to execute, if using + USB_INTERRUPT mode operation). + + In USB low speed applications, the host does not broadcast SOF packets to + the device, so the application firmware becomes responsible for calling + USBIncrement1msInternalTimers() periodically (ex: from a general purpose + timer interrupt handler), or else the returned value from this function will + not increment. + + Prior to calling USBDeviceInit() for the first time the returned value will + be unpredictable. + + This function is USB_INTERRUPT mode safe and may be called from main loop + code without risk of retrieving a partially updated 32-bit number. + + However, this value only increments when the USBDeviceTasks() function is allowed + to execute. If USB_INTERRUPT mode is used, it is allowable to block on this + function. If however USB_POLLING mode is used, one must not block on this + function without also calling USBDeviceTasks() continuously for the blocking + duration (since the USB stack must still be allowed to execute, and the USB + stack is also responsible for updating the tick counter internally). + + If the application is operating in USB_POLLING mode, this function should + only be called from the main loop context, and not from an interrupt handler, + as the returned value could be incorrect, if the main loop context code was in + the process of updating the internal count at the moment of the interrupt event. + ***************************************************************************/ +uint32_t USBGet1msTickCount(void) +{ + #if defined (USB_INTERRUPT) + uint32_t localContextValue; + + //Repeatedly read the interrupt context variable, until we get a stable/unchanging + //value. This ensures that the complete 32-bit value got read without + //getting interrupted in between bytes. + do + { + localContextValue = USB1msTickCount; + }while(localContextValue != USB1msTickCount); + + return localContextValue; + + #else + return USB1msTickCount; + #endif +} + + + + + + +/** EOF USBDevice.c *****************************************************/ diff --git a/src/usb/usb_device_hid.c b/src/usb/usb_device_hid.c new file mode 100644 index 0000000..cb5a7ef --- /dev/null +++ b/src/usb/usb_device_hid.c @@ -0,0 +1,321 @@ +// DOM-IGNORE-BEGIN +/******************************************************************************* +Copyright 2015 Microchip Technology Inc. (www.microchip.com) + +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. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ +//DOM-IGNORE-END + +/******************************************************************************* + USB Device Human Interface Device (HID) Layer + + Company: + Microchip Technology Inc. + + File Name: + usb_device_hid.c + + Summary: + USB Device Human Interface Device (HID) Layer interface API. + + Description: + USB Device Human Interface Device (HID) Layer interface API. +*******************************************************************************/ + + +// ***************************************************************************** +// ***************************************************************************** +// Section: Included Files +// ***************************************************************************** +// ***************************************************************************** +#include "usb_config.h" +#include "usb.h" +#include "usb_device_hid.h" + +// ***************************************************************************** +// ***************************************************************************** +// Section: File Scope or Global Constants +// ***************************************************************************** +// ***************************************************************************** + +// ***************************************************************************** +// ***************************************************************************** +// Section: File Scope Data Types +// ***************************************************************************** +// ***************************************************************************** +typedef struct __attribute__((packed)) +{ + unsigned :8; + unsigned :8; + uint8_t reportId; + uint8_t duration; +} USB_SETUP_SET_IDLE_RATE; + +typedef struct __attribute__((packed)) +{ + unsigned :8; + unsigned :8; + uint8_t protocol; +} USB_SETUP_SET_PROTOCOL; + +// ***************************************************************************** +// ***************************************************************************** +// Section: Variables +// ***************************************************************************** +// ***************************************************************************** +static uint8_t idle_rate; +static uint8_t active_protocol; // [0] Boot Protocol [1] Report Protocol + +extern const struct{uint8_t report[HID_RPT01_SIZE];}hid_rpt01; + +// ***************************************************************************** +// ***************************************************************************** +// Section: Prototypes +// ***************************************************************************** +// ***************************************************************************** +#if defined USER_GET_REPORT_HANDLER + void USER_GET_REPORT_HANDLER(void); +#endif + +#if defined USER_SET_REPORT_HANDLER + extern void USER_SET_REPORT_HANDLER(void); +#endif + +// ***************************************************************************** +// ***************************************************************************** +// Section: Macros or Functions +// ***************************************************************************** +// ***************************************************************************** + +//To implement a set idle rate callback function in the application, +//Make sure "#define USB_DEVICE_HID_IDLE_RATE_CALLBACK(reportID, newIdleRate) USBHIDCBSetIdleRateHandler(reportID, newIdleRate)" +//is placed in your usb_config.h file, and then in your application .c file, +//add the void USBHIDCBSetIdleRateHandler(reportID, newIdleRate) function +//implementation that saves the new idle rate and report ID info, so that it +//gets used later when sending subsequent HID input report packets to the host. +#ifndef USB_DEVICE_HID_IDLE_RATE_CALLBACK + #define USB_DEVICE_HID_IDLE_RATE_CALLBACK(reportId, idleRate) +#else + extern void USB_DEVICE_HID_IDLE_RATE_CALLBACK(uint8_t reportId, uint8_t idleRate); +#endif + +/******************************************************************** + Function: + void USBCheckHIDRequest(void) + + Summary: + This routine handles HID specific request that happen on EP0. + This function should be called from the USBCBCheckOtherReq() call back + function whenever implementing a HID device. + + Description: + This routine handles HID specific request that happen on EP0. These + include, but are not limited to, requests for the HID report + descriptors. This function should be called from the + USBCBCheckOtherReq() call back function whenever using an HID device. + + Typical Usage: + + void USBCBCheckOtherReq(void) + { + //Since the stack didn't handle the request I need to check + // my class drivers to see if it is for them + USBCheckHIDRequest(); + } + + + PreCondition: + None + + Parameters: + None + + Return Values: + None + + Remarks: + None + + *******************************************************************/ +void USBCheckHIDRequest(void) +{ + if(SetupPkt.Recipient != USB_SETUP_RECIPIENT_INTERFACE_BITFIELD) return; + if(SetupPkt.bIntfID != HID_INTF_ID) return; + + /* + * There are two standard requests that hid.c may support. + * 1. GET_DSC(DSC_HID,DSC_RPT,DSC_PHY); + * 2. SET_DSC(DSC_HID,DSC_RPT,DSC_PHY); + */ + if(SetupPkt.bRequest == USB_REQUEST_GET_DESCRIPTOR) + { + switch(SetupPkt.bDescriptorType) + { + case DSC_HID: //HID Descriptor + if(USBActiveConfiguration == 1) + { + USBEP0SendROMPtr( + (const uint8_t*)&configDescriptor1 + 18, //18 is a magic number. It is the offset from start of the configuration descriptor to the start of the HID descriptor. + sizeof(USB_HID_DSC)+3, + USB_EP0_INCLUDE_ZERO); + } + break; + case DSC_RPT: //Report Descriptor + //if(USBActiveConfiguration == 1) + { + USBEP0SendROMPtr( + (const uint8_t*)&hid_rpt01, + HID_RPT01_SIZE, //See usbcfg.h + USB_EP0_INCLUDE_ZERO); + } + break; + case DSC_PHY: //Physical Descriptor + //Note: The below placeholder code is commented out. HID Physical Descriptors are optional and are not used + //in many types of HID applications. If an application does not have a physical descriptor, + //then the device should return STALL in response to this request (stack will do this automatically + //if no-one claims ownership of the control transfer). + //If an application does implement a physical descriptor, then make sure to declare + //hid_phy01 (rom structure containing the descriptor data), and hid_phy01 (the size of the descriptors in uint8_ts), + //and then uncomment the below code. + //if(USBActiveConfiguration == 1) + //{ + // USBEP0SendROMPtr((const uint8_t*)&hid_phy01, sizeof(hid_phy01), USB_EP0_INCLUDE_ZERO); + //} + break; + }//end switch(SetupPkt.bDescriptorType) + }//end if(SetupPkt.bRequest == GET_DSC) + + if(SetupPkt.RequestType != USB_SETUP_TYPE_CLASS_BITFIELD) + { + return; + } + + switch(SetupPkt.bRequest) + { + case GET_REPORT: + #if defined USER_GET_REPORT_HANDLER + USER_GET_REPORT_HANDLER(); + #endif + break; + case SET_REPORT: + #if defined USER_SET_REPORT_HANDLER + USER_SET_REPORT_HANDLER(); + #endif + break; + case GET_IDLE: + USBEP0SendRAMPtr( + (uint8_t*)&idle_rate, + 1, + USB_EP0_INCLUDE_ZERO); + break; + case SET_IDLE: + USBEP0Transmit(USB_EP0_NO_DATA); + idle_rate = SetupPkt.W_Value.byte.HB; + USB_DEVICE_HID_IDLE_RATE_CALLBACK(SetupPkt.W_Value.byte.LB, idle_rate); + break; + case GET_PROTOCOL: + USBEP0SendRAMPtr( + (uint8_t*)&active_protocol, + 1, + USB_EP0_NO_OPTIONS); + break; + case SET_PROTOCOL: + USBEP0Transmit(USB_EP0_NO_DATA); + active_protocol = SetupPkt.W_Value.byte.LB; + break; + }//end switch(SetupPkt.bRequest) + +}//end USBCheckHIDRequest + +/******************************************************************** + Function: + USB_HANDLE HIDTxPacket(uint8_t ep, uint8_t* data, uint16_t len) + + Summary: + Sends the specified data out the specified endpoint + + Description: + This function sends the specified data out the specified + endpoint and returns a handle to the transfer information. + + Typical Usage: + + //make sure that the last transfer isn't busy by checking the handle + if(!HIDTxHandleBusy(USBInHandle)) + { + //Send the data contained in the ToSendDataBuffer[] array out on + // endpoint HID_EP + USBInHandle = HIDTxPacket(HID_EP,(uint8_t*)&ToSendDataBuffer[0],sizeof(ToSendDataBuffer)); + } + + + PreCondition: + None + + Parameters: + uint8_t ep - the endpoint you want to send the data out of + uint8_t* data - pointer to the data that you wish to send + uint16_t len - the length of the data that you wish to send + + Return Values: + USB_HANDLE - a handle for the transfer. This information + should be kept to track the status of the transfer + + Remarks: + None + + *******************************************************************/ + // Implemented as a macro. See usb_function_hid.h + +/******************************************************************** + Function: + USB_HANDLE HIDRxPacket(uint8_t ep, uint8_t* data, uint16_t len) + + Summary: + Receives the specified data out the specified endpoint + + Description: + Receives the specified data out the specified endpoint. + + Typical Usage: + + //Read 64-uint8_ts from endpoint HID_EP, into the ReceivedDataBuffer array. + // Make sure to save the return handle so that we can check it later + // to determine when the transfer is complete. + USBOutHandle = HIDRxPacket(HID_EP,(uint8_t*)&ReceivedDataBuffer,64); + + + PreCondition: + None + + Parameters: + uint8_t ep - the endpoint you want to receive the data into + uint8_t* data - pointer to where the data will go when it arrives + uint16_t len - the length of the data that you wish to receive + + Return Values: + USB_HANDLE - a handle for the transfer. This information + should be kept to track the status of the transfer + + Remarks: + None + + *******************************************************************/ + // Implemented as a macro. See usb_function_hid.h + +/******************************************************************************* + End of File +*/ diff --git a/src/usb/usb_events.c b/src/usb/usb_events.c new file mode 100644 index 0000000..eb6c51f --- /dev/null +++ b/src/usb/usb_events.c @@ -0,0 +1,118 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +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. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ + +/** INCLUDES *******************************************************/ +#include "system.h" + +#include "usb.h" +#include "usb_device_hid.h" + +#include "joystick.h" +#include "app_led_usb_status.h" + +/******************************************************************* + * Function: bool USER_USB_CALLBACK_EVENT_HANDLER( + * USB_EVENT event, void *pdata, uint16_t size) + * + * PreCondition: None + * + * Input: USB_EVENT event - the type of event + * void *pdata - pointer to the event data + * uint16_t 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(USB_EVENT event, void *pdata, uint16_t size) +{ + switch( (int) event ) + { + case EVENT_TRANSFER: + break; + + case EVENT_SOF: + /* We are using the SOF as a timer to time the LED indicator. Call + * the LED update function here. */ + APP_LEDUpdateUSBStatus(); + break; + + case EVENT_SUSPEND: + /* Update the LED status for the suspend event. */ + APP_LEDUpdateUSBStatus(); + + //Call the hardware platform specific handler for suspend events for + //possible further action (like optionally going reconfiguring the application + //for lower power states and going to sleep during the suspend event). This + //would normally be done in USB compliant bus powered applications, although + //no further processing is needed for purely self powered applications that + //don't consume power from the host. + SYSTEM_Initialize(SYSTEM_STATE_USB_SUSPEND); + break; + + case EVENT_RESUME: + /* Update the LED status for the resume event. */ + APP_LEDUpdateUSBStatus(); + + //Call the hardware platform specific resume from suspend handler (ex: to + //restore I/O pins to higher power states if they were changed during the + //preceding SYSTEM_Initialize(SYSTEM_STATE_USB_SUSPEND) call at the start + //of the suspend condition. + SYSTEM_Initialize(SYSTEM_STATE_USB_RESUME); + break; + + case EVENT_CONFIGURED: + /* When the device is configured, we can (re)initialize the demo + * code. */ + JoystickInitialize(); + break; + + case EVENT_SET_DESCRIPTOR: + break; + + case EVENT_EP0_REQUEST: + /* We have received a non-standard USB request. The HID driver + * needs to check to see if the request was for it. */ + USBCheckHIDRequest(); + break; + + case EVENT_BUS_ERROR: + break; + + case EVENT_TRANSFER_TERMINATED: + break; + + default: + break; + } + return true; +} + + +/******************************************************************************* + End of File +*/ +