00001 /* ---------------------------------------------------------------------------- 00002 * SAM Software Package License 00003 * ---------------------------------------------------------------------------- 00004 * Copyright (c) 2014, Atmel Corporation 00005 * 00006 * All rights reserved. 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions are met: 00010 * 00011 * - Redistributions of source code must retain the above copyright notice, 00012 * this list of conditions and the disclaimer below. 00013 * 00014 * Atmel's name may not be used to endorse or promote products derived from 00015 * this software without specific prior written permission. 00016 * 00017 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR 00018 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00019 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE 00020 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, 00021 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00022 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 00023 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00024 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00025 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 00026 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00027 * ---------------------------------------------------------------------------- 00028 */ 00029 /** \cond usb_hid_keyboard 00030 * \page usb_hid_keyboard USB HID Keyboard Example 00031 * 00032 * \section Purpose 00033 * 00034 * The USB HID Keyboard Example will help you to get familiar with the 00035 * USB Device Port(UDP) and PIO interface on SAMv7 microcontrollers. Also 00036 * it can help you to be familiar with the USB Framework that is used for 00037 * rapid development of USB-compliant class drivers such as USB human 00038 * Interface Device class (HID). 00039 * 00040 * \section Description 00041 * 00042 * The demo simulates a simple keyboard with a caps lock and 'a' on it. 00043 * 00044 * When an Xplained board running this program connected to a host (PC for 00045 * example), with USB cable, the Xplained board appears as a HID Keyboard for 00046 * the host. Then you can use the push buttons on the Xplained board to input 00047 * letter to the host. E.g, to open a editor and input a letter 'a'. 00048 * 00049 * \section Usage 00050 * 00051 * -# Build the program and download it inside the SAM V71 Xplained Ultra board. 00052 * Please refer to the Getting Started with SAM V71 Microcontrollers.pdf 00053 * -# On the computer, open and configure a terminal application 00054 * (e.g. HyperTerminal on Microsoft Windows) with these settings: 00055 * - 115200 bauds 00056 * - 8 bits of data 00057 * - No parity 00058 * - 1 stop bit 00059 * - No flow control 00060 * -# Start the application. 00061 * -# In the terminal window, the following text should appear: 00062 * \code 00063 * -- USB Device HID Keyboard Project xxx -- 00064 * -- SAMxxxxx-xx 00065 * -- Compiled: xxx xx xxxx xx:xx:xx -- 00066 * \endcode 00067 * -# When connecting USB cable to windows, the 00068 * new "HID Keyboard Device" appears in the 00069 * hardware %device list. 00070 * -# Once the device is connected and configured, pressing any of the board 00071 * buttons should send characters to the host PC. Pressing num. lock should 00072 * also make the third LED toggle its state (on/off). 00073 * 00074 * \section References 00075 * - usb_hid_keyboard/main.c 00076 * - pio: PIO interface driver 00077 * - pio.h 00078 * - pio_it.h 00079 * - usb: USB Framework, USB HID driver and UDP interface driver 00080 * - \ref usbd_framework 00081 * - \ref usbd_api 00082 * - \ref usbd_hid_kbd_drv 00083 */ 00084 00085 /** 00086 * \file 00087 * 00088 * This file contains all the specific code for the 00089 * usb_hid_keyboard 00090 * 00091 * \section Contents 00092 * 00093 * The code can be roughly broken down as follows: 00094 * - Configuration functions 00095 * - VBus_Configure 00096 * - ConfigurePit 00097 * - ConfigureWakeUp 00098 * - PIO & Timer configurations in start of main 00099 * - Interrupt handlers 00100 * - ISR_Vbus 00101 * - ISR_Pit 00102 * - WakeUpHandler 00103 * - Callback functions 00104 * - HIDDKeyboardCallbacks_LedsChanged 00105 * - The main function, which implements the program behavior 00106 * 00107 */ 00108 00109 /*----------------------------------------------------------------------------- 00110 * Headers 00111 *-----------------------------------------------------------------------------*/ 00112 00113 #include "board.h" 00114 00115 #include "USBD.h" 00116 #include "HIDDKeyboardDriver.h" 00117 #include "USBD_LEDs.h" 00118 00119 #include <string.h> 00120 #include <stdbool.h> 00121 #include <stdint.h> 00122 00123 00124 /*----------------------------------------------------------------------------- 00125 * Definitions 00126 *-----------------------------------------------------------------------------*/ 00127 #define NO_PUSHBUTTON 00128 00129 /** Number of keys used in the example. */ 00130 #define NUM_KEYS 2 00131 00132 /** Number of non-modifiers keys. */ 00133 #define NUM_NORMAL_KEYS 1 00134 00135 /** Number of modifier keys. */ 00136 #define NUM_MODIFIER_KEYS (NUM_KEYS - NUM_NORMAL_KEYS) 00137 00138 /** Num lock LED index. */ 00139 #define LED_NUMLOCK USBD_LEDOTHER 00140 00141 /*--------------------------------------------------------------------------- 00142 * External variables 00143 *---------------------------------------------------------------------------*/ 00144 00145 /** Descriptor list for HID keyboard device */ 00146 extern USBDDriverDescriptors hiddKeyboardDriverDescriptors; 00147 00148 /*--------------------------------------------------------------------------- 00149 * Internal variables 00150 *---------------------------------------------------------------------------*/ 00151 00152 #ifdef NO_PUSHBUTTON 00153 #else 00154 /** List of pinsPushButtons to configure for the application. */ 00155 static Pin pinsPushButtons[] = {PINS_PUSHBUTTONS}; 00156 #endif 00157 00158 /** Array of key codes produced by each button. */ 00159 static uint8_t keyCodes[NUM_KEYS] = { 00160 HIDKeypad_A, 00161 HIDKeypad_NUMLOCK, 00162 }; 00163 00164 /** Current status (pressed or not) for each key. */ 00165 static uint8_t keyStatus[NUM_KEYS]; 00166 00167 /*--------------------------------------------------------------------------- 00168 * Callbacks re-implementation 00169 *---------------------------------------------------------------------------*/ 00170 00171 /** 00172 * Invoked whenever a SETUP request is received from the host. Forwards the 00173 * request to the standard handler. 00174 */ 00175 void USBDCallbacks_RequestReceived(const USBGenericRequest *request) 00176 { 00177 HIDDKeyboardDriver_RequestHandler(request); 00178 } 00179 00180 /** 00181 * Invoked when the configuration of the device changes. Start reading 00182 * output reports. 00183 * \param cfgnum New configuration number. 00184 */ 00185 void USBDDriverCallbacks_ConfigurationChanged(uint8_t cfgnum) 00186 { 00187 HIDDKeyboardDriver_ConfigurationChangedHandler(cfgnum); 00188 } 00189 00190 /** 00191 * Invoked when the status of the keyboard LEDs changes. Turns the num. lock 00192 * LED on or off. 00193 * \param numLockStatus Indicates the current status of the num. lock key. 00194 * \param capsLockStatus Indicates the current status of the caps lock key. 00195 * \param scrollLockStatus Indicates the current status of the scroll lock key. 00196 */ 00197 void HIDDKeyboardCallbacks_LedsChanged( 00198 uint8_t numLockStatus, 00199 uint8_t capsLockStatus, 00200 uint8_t scrollLockStatus) 00201 { 00202 printf("%c %c %c\n\r", 00203 numLockStatus ? 'N':'_', 00204 capsLockStatus ? 'C':'_', 00205 scrollLockStatus ? 'S':'_' 00206 ); 00207 /* Num. lock */ 00208 if (numLockStatus) { 00209 LED_Set(LED_NUMLOCK); 00210 } else { 00211 LED_Clear(LED_NUMLOCK); 00212 } 00213 } 00214 00215 /*---------------------------------------------------------------------------- 00216 * Internal functions 00217 *----------------------------------------------------------------------------*/ 00218 /** 00219 * Configure USB settings for USB device 00220 */ 00221 static void _ConfigureUotghs(void) 00222 { 00223 00224 /* UTMI parallel mode, High/Full/Low Speed */ 00225 /* UUSBCK not used in this configuration (High Speed) */ 00226 PMC->PMC_SCDR = PMC_SCDR_USBCLK; 00227 /* USB clock register: USB Clock Input is UTMI PLL */ 00228 PMC->PMC_USB = PMC_USB_USBS; 00229 /* Enable peripheral clock for USBHS */ 00230 PMC_EnablePeripheral(ID_USBHS); 00231 USBHS->USBHS_CTRL = USBHS_CTRL_UIMOD_DEVICE; 00232 /* Enable PLL 480 MHz */ 00233 PMC->CKGR_UCKR = CKGR_UCKR_UPLLEN | CKGR_UCKR_UPLLCOUNT(0xF); 00234 /* Wait that PLL is considered locked by the PMC */ 00235 while( !(PMC->PMC_SR & PMC_SR_LOCKU) ); 00236 00237 /* IRQ */ 00238 NVIC_EnableIRQ(USBHS_IRQn) ; 00239 } 00240 00241 00242 /*--------------------------------------------------------------------------- 00243 * Exported function 00244 *---------------------------------------------------------------------------*/ 00245 00246 /** 00247 * Initializes the system and then monitors buttons, sending the 00248 * corresponding character when one is pressed. 00249 * \callgraph 00250 */ 00251 int main(void) 00252 { 00253 uint32_t i; 00254 00255 /* Disable watchdog */ 00256 WDT_Disable( WDT ); 00257 00258 printf("-- USB Device HID Keyboard Project %s --\n\r", SOFTPACK_VERSION); 00259 printf("-- %s\n\r", BOARD_NAME); 00260 printf( "-- Compiled: %s %s With %s--\n\r", __DATE__, __TIME__ , COMPILER_NAME) ; 00261 00262 SCB_EnableICache(); 00263 SCB_EnableDCache(); 00264 00265 /* If they are present, configure Vbus & Wake-up pins */ 00266 PIO_InitializeInterrupts(0); 00267 00268 _ConfigureUotghs(); 00269 00270 #ifdef NO_PUSHBUTTON 00271 printf( "-- : DBG key 1 2 used as buttons\n\r" ); 00272 printf( "-- : 1st press to push, 2nd press to release\n\r" ); 00273 #else 00274 /* Initialize key statuses and configure push buttons */ 00275 PIO_Configure(pinsPushButtons, PIO_LISTSIZE(pinsPushButtons)); 00276 #endif 00277 memset(keyStatus, 1, NUM_KEYS); 00278 00279 /* Configure LEDs */ 00280 LED_Configure(LED_NUMLOCK); 00281 00282 /* HID driver initialization */ 00283 HIDDKeyboardDriver_Initialize(&hiddKeyboardDriverDescriptors); 00284 00285 // Start USB stack to authorize VBus monitoring 00286 USBD_Connect(); 00287 00288 00289 /* Infinite loop */ 00290 while (1) { 00291 uint8_t pressedKeys[NUM_KEYS]; 00292 uint8_t pressedKeysSize = 0; 00293 uint8_t releasedKeys[NUM_KEYS]; 00294 uint8_t releasedKeysSize = 0; 00295 00296 if (USBD_GetState() < USBD_STATE_CONFIGURED) 00297 continue; 00298 /* Monitor buttons */ 00299 #ifdef NO_PUSHBUTTON 00300 if (DBG_IsRxReady()) { 00301 uint8_t key = DBG_GetChar(); 00302 switch(key) { 00303 case '1': case '2': 00304 i = key - '1'; 00305 if (keyStatus[i]) { 00306 /* Key press simulation */ 00307 TRACE_INFO("Key %u pressed\n\r", (unsigned int)i); 00308 keyStatus[i] = 0; 00309 pressedKeys[pressedKeysSize] = keyCodes[i]; 00310 pressedKeysSize ++; 00311 HIDDKeyboard_RemoteWakeUp(); 00312 } else { 00313 /* Key release simulation */ 00314 TRACE_INFO("Key %u released\n\r", (unsigned int)i); 00315 keyStatus[i] = 1; 00316 releasedKeys[releasedKeysSize] = keyCodes[i]; 00317 releasedKeysSize++; 00318 } 00319 break; 00320 default: DBG_PutChar(key); 00321 } 00322 } 00323 #else 00324 for (i=0; i < PIO_LISTSIZE(pinsPushButtons); i++) { 00325 /* Check if button state has changed */ 00326 uint8_t isButtonPressed = PIO_Get(&(pinsPushButtons[i])); 00327 if (isButtonPressed != keyStatus[i]) { 00328 /* Update button state */ 00329 if (!isButtonPressed) { 00330 /* Key has been pressed */ 00331 printf("BP %u pressed\n\r", (unsigned int)i); 00332 keyStatus[i] = 0; 00333 pressedKeys[pressedKeysSize] = keyCodes[i]; 00334 pressedKeysSize++; 00335 HIDDKeyboardDriver_RemoteWakeUp(); 00336 } else { 00337 /* Key has been released */ 00338 printf("BP %u released\n\r", (unsigned int)i); 00339 keyStatus[i] = 1; 00340 releasedKeys[releasedKeysSize] = keyCodes[i]; 00341 releasedKeysSize++; 00342 } 00343 } 00344 } 00345 #endif 00346 00347 /* Update key status in the HID driver if necessary */ 00348 if ((pressedKeysSize != 0) || (releasedKeysSize != 0)) { 00349 uint8_t status; 00350 do { 00351 status = HIDDKeyboardDriver_ChangeKeys(pressedKeys, 00352 pressedKeysSize, 00353 releasedKeys, 00354 releasedKeysSize); 00355 } 00356 while (status != USBD_STATUS_SUCCESS); 00357 } 00358 } 00359 } 00360 /** \endcond */