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_iad_cdc_hid 00030 * \page usb_iad_cdc_hid USB CDC(Serial)+HID(Keyboard) Example 00031 * 00032 * \section Purpose 00033 * 00034 * The USB CDCHID Project will help you to get familiar with the 00035 * USB Device Port(UDP)interface .Also it can help you to be familiar with the USB 00036 * Framework that is used for rapid development of USB-compliant class 00037 * drivers such as USB Communication Device class (CDC), and how to combine 00038 * two USB functions to a single composite device (such as CDC + HID). 00039 * 00040 * \section Requirements 00041 * 00042 * This package can be used with some of Atmel Xplained board that have UDP 00043 * interface, depending on the functions included. 00044 * 00045 * \section win_drv_update Windows Driver Update 00046 * 00047 * The composite device is generally supported by Microsoft windows, but some 00048 * patches are needed for muti-interface functions such as CDC & Audio. 00049 * 00050 * \section Description 00051 * 00052 * This demo simulates a USB composite device that has USB Serial RS232 00053 * Converter and USB HID Keyboard functions. 00054 * 00055 * When the board running this program connected to a host (PC for example), with 00056 * USB cable, host will notice the attachment of a USB device. No device 00057 * driver offered for the device now. 00058 * 00059 * \section Usage 00060 * 00061 * -# Build the program and download it inside the SAM V71 Xplained Ultra board. 00062 * Please refer to the Getting Started with SAM V71 Microcontrollers.pdf 00063 * -# On the computer, open and configure a terminal application 00064 * (e.g. HyperTerminal on Microsoft Windows) with these settings: 00065 * - 115200 bauds 00066 * - 8 bits of data 00067 * - No parity 00068 * - 1 stop bit 00069 * - No flow control 00070 * -# Start the application. 00071 * -# In the terminal window, the following text should appear: 00072 * \code 00073 * -- USB CDC HID Device Project xxx -- 00074 * -- SAMxxxxx-xx 00075 * -- Compiled: xxx xx xxxx xx:xx:xx -- 00076 * \endcode 00077 * -# When connecting USB cable to windows, the LED blinks, and the host 00078 * reports a new USB device attachment. 00079 * -# For the windows driver installation and the test functions, please 00080 * refer to "USB CDC serial converter" & 00081 * "USB HID Keyboard Project". 00082 * -# You can use the inf file 00083 * libraries\\usb\\device\\composite\\drv\\CompositeCDCSerial.inf 00084 * to install the CDC serial port. 00085 * 00086 * \section Reference 00087 * - usb_iad_cdc_hid/main.c 00088 * - pio: Pin configurations and peripheral configure. 00089 * - usb: USB Device Framework, USB CDC driver and UDP interface driver 00090 * - \ref usbd_framework 00091 * - \ref usbd_api 00092 * - \ref usbd_composite "composite" 00093 * - \ref usbd_composite_drv 00094 * - \ref usbd_hid "hid" \\ \ref usbd_hid_key "hid-keyboard" 00095 * - \ref usbd_hid_kbd_drv 00096 * - \ref usbd_cdc "cdc-serial" 00097 * - \ref usbd_cdc_serial_drv 00098 * - projects: 00099 * - \ref usb_hid_keyboard 00100 * - \ref usb_cdc_serial 00101 * 00102 */ 00103 00104 /** 00105 * \file 00106 * 00107 * This file contains all the specific code for the 00108 * usb_iad_cdc_hid project 00109 */ 00110 00111 /*---------------------------------------------------------------------------- 00112 * Headers 00113 *----------------------------------------------------------------------------*/ 00114 00115 #include "board.h" 00116 00117 #include <USBD_Config.h> 00118 #include <USBD_LEDs.h> 00119 00120 #include <CDCHIDDDriver.h> 00121 #include <CDCDSerial.h> 00122 #include <HIDDKeyboard.h> 00123 00124 #include <string.h> 00125 #include <stdbool.h> 00126 #include <stdint.h> 00127 #include <stdio.h> 00128 00129 /*--------------------------------------------------------------------------- 00130 * Definitions 00131 *---------------------------------------------------------------------------*/ 00132 #define NO_PUSHBUTTON 00133 /** Number of keys used in the example. */ 00134 #define NUM_KEYS 2 00135 00136 /** Number of non-modifiers keys. */ 00137 #define NUM_NORMAL_KEYS 1 00138 00139 /** Number of modifier keys. */ 00140 #define NUM_MODIFIER_KEYS (NUM_KEYS - NUM_NORMAL_KEYS) 00141 00142 /** NumLock LED index. */ 00143 #define LED_NUMLOCK USBD_LEDOTHER 00144 00145 /** Size in bytes of the packet used for reading data from USB */ 00146 #define DATAPACKETSIZE \ 00147 CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCDSerialDriverDescriptors_DATAIN) 00148 00149 /** Size in bytes of the buffer used for reading data from the USB & USART */ 00150 #define DATABUFFERSIZE (DATAPACKETSIZE+2) 00151 00152 /*---------------------------------------------------------------------------- 00153 * External variables 00154 *----------------------------------------------------------------------------*/ 00155 00156 extern const USBDDriverDescriptors cdchiddDriverDescriptors; 00157 00158 /*--------------------------------------------------------------------------- 00159 * Internal variables 00160 *---------------------------------------------------------------------------*/ 00161 00162 /** Buffer for storing incoming USB data. */ 00163 static unsigned char usbSerialBuffer0[DATABUFFERSIZE]; 00164 00165 /** Serial port opened */ 00166 static unsigned char isSerialPortON = 0; 00167 00168 /*- HID */ 00169 00170 #ifdef NO_PUSHBUTTON 00171 #else 00172 /** List of pinsPushButtons to configure for the application. */ 00173 static Pin pinsPushButtons[] = {PINS_PUSHBUTTONS}; 00174 #endif 00175 00176 /** Array of key codes produced by each button. */ 00177 static uint8_t keyCodes[NUM_KEYS] = { 00178 HIDKeypad_A, 00179 HIDKeypad_NUMLOCK, 00180 }; 00181 00182 /** Current status (pressed or not) for each key. */ 00183 static uint8_t keyStatus[NUM_KEYS]; 00184 00185 /*----------------------------------------------------------------------------- 00186 * Callback re-implementation 00187 *-----------------------------------------------------------------------------*/ 00188 00189 00190 00191 /** 00192 * Invoked when the configuration of the device changes. Parse used endpoints. 00193 * \param cfgnum New configuration number. 00194 */ 00195 void USBDDriverCallbacks_ConfigurationChanged(uint8_t cfgnum) 00196 { 00197 CDCHIDDDriver_ConfigurationChangedHandler(cfgnum); 00198 } 00199 00200 /** 00201 * Invoked when a new SETUP request is received from the host. Forwards the 00202 * request to the Mass Storage device driver handler function. 00203 * \param request Pointer to a USBGenericRequest instance. 00204 */ 00205 void USBDCallbacks_RequestReceived(const USBGenericRequest *request) 00206 { 00207 CDCHIDDDriver_RequestHandler(request); 00208 } 00209 00210 /*---------------------------------------------------------------------------- 00211 * Callbacks 00212 *----------------------------------------------------------------------------*/ 00213 00214 /** 00215 * Invoked when the CDC ControlLineState is changed 00216 * \param DTR New DTR value. 00217 * \param RTS New RTS value. 00218 */ 00219 void CDCDSerial_ControlLineStateChanged(uint8_t DTR, 00220 uint8_t RTS) 00221 { 00222 isSerialPortON = DTR; 00223 RTS = RTS; /* dummy */ 00224 } 00225 00226 /** 00227 * Invoked when the status of the keyboard LEDs changes. Turns the num. lock 00228 * LED on or off. 00229 * \param numLockStatus Indicates the current status of the num. lock key. 00230 * \param capsLockStatus Indicates the current status of the caps lock key. 00231 * \param scrollLockStatus Indicates the current status of the scroll lock key 00232 */ 00233 void HIDDKeyboardCallbacks_LedsChanged( 00234 uint8_t numLockStatus, 00235 uint8_t capsLockStatus, 00236 uint8_t scrollLockStatus) 00237 { 00238 capsLockStatus = capsLockStatus; 00239 scrollLockStatus = scrollLockStatus; 00240 /* Num. lock */ 00241 if (numLockStatus) { 00242 LED_Set(LED_NUMLOCK); 00243 } else { 00244 LED_Clear(LED_NUMLOCK); 00245 } 00246 } 00247 00248 /*--------------------------------------------------------------------------- 00249 * Internal functions 00250 *---------------------------------------------------------------------------*/ 00251 00252 /** 00253 * Monitor keyboard buttons & Update key status in HID driver 00254 */ 00255 static void _HIDDKeyboardProcessKeys(void) 00256 { 00257 uint32_t i; 00258 uint8_t pressedKeys[NUM_KEYS]; 00259 uint8_t pressedKeysSize = 0; 00260 uint8_t releasedKeys[NUM_KEYS]; 00261 uint8_t releasedKeysSize = 0; 00262 00263 /* Monitor buttons */ 00264 #ifdef NO_PUSHBUTTON 00265 if (DBG_IsRxReady()) { 00266 uint8_t key = DBG_GetChar(); 00267 switch(key) { 00268 case '1': case '2': 00269 i = key - '1'; 00270 if (keyStatus[i]) { 00271 /* Key press simulation */ 00272 TRACE_INFO("Key %u pressed\n\r", (unsigned int)i); 00273 keyStatus[i] = 0; 00274 pressedKeys[pressedKeysSize] = keyCodes[i]; 00275 pressedKeysSize ++; 00276 HIDDKeyboard_RemoteWakeUp(); 00277 } else { 00278 /* Key release simulation */ 00279 TRACE_INFO("Key %u released\n\r", (unsigned int)i); 00280 keyStatus[i] = 1; 00281 releasedKeys[releasedKeysSize] = keyCodes[i]; 00282 releasedKeysSize++; 00283 } 00284 break; 00285 default: DBG_PutChar(key); 00286 } 00287 } 00288 #else 00289 for (i=0; i < PIO_LISTSIZE(pinsPushButtons); i++) { 00290 /* Check if button state has changed */ 00291 uint8_t isButtonPressed = PIO_Get(&(pinsPushButtons[i])); 00292 if (isButtonPressed != keyStatus[i]) { 00293 /* Update button state */ 00294 if (!isButtonPressed) { 00295 /* Key has been pressed */ 00296 TRACE_INFO("Key %u has been pressed\n\r", i); 00297 keyStatus[i] = 0; 00298 pressedKeys[pressedKeysSize] = keyCodes[i]; 00299 pressedKeysSize++; 00300 HIDDKeyboard_RemoteWakeUp(); 00301 } else { 00302 /* Key has been released */ 00303 TRACE_INFO("Key %u has been released\n\r", i); 00304 keyStatus[i] = 1; 00305 releasedKeys[releasedKeysSize] = keyCodes[i]; 00306 releasedKeysSize++; 00307 } 00308 } 00309 } 00310 #endif 00311 00312 /* Update key status in the HID driver if necessary */ 00313 if ((pressedKeysSize != 0) || (releasedKeysSize != 0)) { 00314 uint8_t status; 00315 do { 00316 status = HIDDKeyboard_ChangeKeys(pressedKeys, 00317 pressedKeysSize, 00318 releasedKeys, 00319 releasedKeysSize); 00320 } while (status != USBD_STATUS_SUCCESS); 00321 } 00322 } 00323 00324 /** 00325 * Configure USBHS settings for USB device 00326 */ 00327 static void _ConfigureUotghs(void) 00328 { 00329 /* UTMI parallel mode, High/Full/Low Speed */ 00330 /* UUSBCK not used in this configuration (High Speed) */ 00331 PMC->PMC_SCDR = PMC_SCDR_USBCLK; 00332 /* USB clock register: USB Clock Input is UTMI PLL */ 00333 PMC->PMC_USB = PMC_USB_USBS; 00334 /* Enable peripheral clock for USBHS */ 00335 PMC_EnablePeripheral(ID_USBHS); 00336 USBHS->USBHS_CTRL = USBHS_CTRL_UIMOD_DEVICE; 00337 /* Enable PLL 480 MHz */ 00338 PMC->CKGR_UCKR = CKGR_UCKR_UPLLEN | CKGR_UCKR_UPLLCOUNT(0xF); 00339 /* Wait that PLL is considered locked by the PMC */ 00340 while( !(PMC->PMC_SR & PMC_SR_LOCKU) ); 00341 00342 /* IRQ */ 00343 NVIC_EnableIRQ(USBHS_IRQn) ; 00344 } 00345 00346 /*--------------------------------------------------------------------------- 00347 * Exported function 00348 *---------------------------------------------------------------------------*/ 00349 /** 00350 * Initializes drivers and start the USB CDCHID device. 00351 */ 00352 int main(void) 00353 { 00354 uint8_t usbConnected = 0, serialON = 0; 00355 00356 /* Disable watchdog */ 00357 WDT_Disable( WDT ); 00358 00359 SCB_EnableICache(); 00360 SCB_EnableDCache(); 00361 00362 printf("-- USB CDC HID Device Project %s --\n\r", SOFTPACK_VERSION); 00363 printf("-- %s\n\r", BOARD_NAME); 00364 printf( "-- Compiled: %s %s With %s--\n\r", __DATE__, __TIME__ , COMPILER_NAME) ; 00365 00366 /* If they are present, configure Vbus & Wake-up pins */ 00367 PIO_InitializeInterrupts(0); 00368 00369 /* If there is on board power, switch it off */ 00370 _ConfigureUotghs(); 00371 00372 /* ----- HID Function Initialize */ 00373 #ifdef NO_PUSHBUTTON 00374 printf( "-- : DBG key 1 2 used as buttons\n\r" ); 00375 printf( "-- : 1st press to push, 2nd press to release\n\r" ); 00376 #else 00377 /* Initialize key statuses and configure push buttons */ 00378 PIO_Configure(pinsPushButtons, PIO_LISTSIZE(pinsPushButtons)); 00379 #endif 00380 memset(keyStatus, 1, NUM_KEYS); 00381 00382 /* Configure LEDs */ 00383 LED_Configure(LED_NUMLOCK); 00384 00385 00386 /* USB CDCHID driver initialization */ 00387 CDCHIDDDriver_Initialize(&cdchiddDriverDescriptors); 00388 00389 /* connect if needed */ 00390 USBD_Connect(); 00391 00392 /* Driver loop */ 00393 while (1) { 00394 /* Device is not configured */ 00395 if (USBD_GetState() < USBD_STATE_CONFIGURED) { 00396 if (usbConnected) { 00397 printf("-I- USB Disconnect/Suspend\n\r"); 00398 usbConnected = 0; 00399 /* Serial port closed */ 00400 isSerialPortON = 0; 00401 } 00402 } else { 00403 if (usbConnected == 0) { 00404 printf("-I- USB Connect\n\r"); 00405 usbConnected = 1; 00406 } 00407 if (!serialON && isSerialPortON) { 00408 printf("-I- SerialPort ON\n\r"); 00409 /* Start receiving data on the USB */ 00410 CDCDSerial_Read(usbSerialBuffer0, 00411 DATAPACKETSIZE, 00412 0, 00413 0); 00414 serialON = 1; 00415 } else if (serialON && !isSerialPortON) { 00416 printf("-I- SeriaoPort OFF\n\r"); 00417 serialON = 0; 00418 } 00419 _HIDDKeyboardProcessKeys(); 00420 } 00421 } 00422 } 00423 /** \endcond */