2012-06-26 06:55:45 +00:00
/*
* Copyright 2012 Jun Wako < wakojun @ gmail . com >
2012-06-27 09:31:33 +00:00
* This file is based on :
* LUFA - 120219 / Demos / Device / Lowlevel / KeyboardMouse
* LUFA - 120219 / Demos / Device / Lowlevel / GenericHID
2012-06-26 06:55:45 +00:00
*/
/*
LUFA Library
Copyright ( C ) Dean Camera , 2012.
dean [ at ] fourwalledcubicle [ dot ] com
www . lufa - lib . org
*/
/*
Copyright 2012 Dean Camera ( dean [ at ] fourwalledcubicle [ dot ] com )
Copyright 2010 Denver Gingerich ( denver [ at ] ossguy [ dot ] com )
Permission to use , copy , modify , distribute , and sell this
software and its documentation for any purpose is hereby granted
without fee , provided that the above copyright notice appear in
all copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation , and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific , written prior permission .
The author disclaim all warranties with regard to this
software , including all implied warranties of merchantability
and fitness . In no event shall the author be liable for any
special , indirect or consequential damages or any damages
whatsoever resulting from loss of use , data or profits , whether
in an action of contract , negligence or other tortious action ,
arising out of or in connection with the use or performance of
this software .
*/
# include "report.h"
# include "host.h"
# include "host_driver.h"
# include "keyboard.h"
2012-06-27 09:31:33 +00:00
# include "sendchar.h"
# include "debug.h"
2012-06-28 03:59:17 +00:00
# include "descriptor.h"
2012-06-26 06:55:45 +00:00
# include "lufa.h"
2012-06-29 07:48:36 +00:00
static uint8_t idle_duration = 0 ;
static uint8_t protocol_report = 1 ;
2012-06-26 06:55:45 +00:00
static uint8_t keyboard_led_stats = 0 ;
2012-06-28 03:59:17 +00:00
static report_keyboard_t keyboard_report_sent ;
2012-06-29 07:48:36 +00:00
2012-06-26 06:55:45 +00:00
/* Host driver */
static uint8_t keyboard_leds ( void ) ;
static void send_keyboard ( report_keyboard_t * report ) ;
static void send_mouse ( report_mouse_t * report ) ;
static void send_system ( uint16_t data ) ;
static void send_consumer ( uint16_t data ) ;
2012-08-25 06:49:08 +00:00
host_driver_t lufa_driver = {
2012-06-26 06:55:45 +00:00
keyboard_leds ,
send_keyboard ,
send_mouse ,
send_system ,
send_consumer
} ;
2012-08-25 06:49:08 +00:00
/*******************************************************************************
* Console
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-07-13 17:47:29 +00:00
# ifdef CONSOLE_ENABLE
2012-07-08 14:57:25 +00:00
static void Console_Task ( void )
2012-06-28 03:59:17 +00:00
{
2012-07-08 14:57:25 +00:00
/* Device must be connected and configured for the task to run */
if ( USB_DeviceState ! = DEVICE_STATE_Configured )
2012-09-06 03:38:39 +00:00
return ;
2012-07-08 14:57:25 +00:00
uint8_t ep = Endpoint_GetCurrentEndpoint ( ) ;
#if 0
// TODO: impl receivechar()/recvchar()
Endpoint_SelectEndpoint ( CONSOLE_OUT_EPNUM ) ;
/* Check to see if a packet has been sent from the host */
if ( Endpoint_IsOUTReceived ( ) )
{
/* Check to see if the packet contains data */
if ( Endpoint_IsReadWriteAllowed ( ) )
{
/* Create a temporary buffer to hold the read in report from the host */
uint8_t ConsoleData [ CONSOLE_EPSIZE ] ;
/* Read Console Report Data */
Endpoint_Read_Stream_LE ( & ConsoleData , sizeof ( ConsoleData ) , NULL ) ;
/* Process Console Report Data */
//ProcessConsoleHIDReport(ConsoleData);
}
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearOUT ( ) ;
}
# endif
/* IN packet */
Endpoint_SelectEndpoint ( CONSOLE_IN_EPNUM ) ;
2012-09-06 03:38:39 +00:00
if ( ! Endpoint_IsEnabled ( ) | | ! Endpoint_IsConfigured ( ) ) {
Endpoint_SelectEndpoint ( ep ) ;
return ;
}
2012-07-13 17:47:29 +00:00
// fill empty bank
while ( Endpoint_IsReadWriteAllowed ( ) )
Endpoint_Write_8 ( 0 ) ;
2012-07-08 14:57:25 +00:00
// flash senchar packet
if ( Endpoint_IsINReady ( ) ) {
Endpoint_ClearIN ( ) ;
}
Endpoint_SelectEndpoint ( ep ) ;
2012-06-28 03:59:17 +00:00
}
2012-07-13 17:47:29 +00:00
# else
static void Console_Task ( void )
{
}
# endif
2012-06-28 03:59:17 +00:00
/*******************************************************************************
* USB Events
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-06-26 06:55:45 +00:00
/** Event handler for the USB_Connect event. */
void EVENT_USB_Device_Connect ( void )
{
}
/** Event handler for the USB_Disconnect event. */
void EVENT_USB_Device_Disconnect ( void )
{
}
2012-07-08 14:57:25 +00:00
void EVENT_USB_Device_StartOfFrame ( void )
{
2012-07-13 17:47:29 +00:00
Console_Task ( ) ;
2012-07-08 14:57:25 +00:00
}
2012-06-26 06:55:45 +00:00
/** Event handler for the USB_ConfigurationChanged event.
* This is fired when the host sets the current configuration of the USB device after enumeration .
*/
2013-02-11 13:56:30 +00:00
# if LUFA_VERSION_INTEGER < 0x120730
/* old API 120219 */
# define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint(epnum, eptype, epdir, epsize, epbank)
# else
/* new API >= 120730 */
# define ENDPOINT_BANK_SINGLE 1
# define ENDPOINT_BANK_DOUBLE 2
# define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint((epdir) | (epnum) , eptype, epsize, epbank)
# endif
2012-06-26 06:55:45 +00:00
void EVENT_USB_Device_ConfigurationChanged ( void )
{
bool ConfigSuccess = true ;
/* Setup Keyboard HID Report Endpoints */
2013-02-11 13:56:30 +00:00
ConfigSuccess & = ENDPOINT_CONFIG ( KEYBOARD_IN_EPNUM , EP_TYPE_INTERRUPT , ENDPOINT_DIR_IN ,
KEYBOARD_EPSIZE , ENDPOINT_BANK_SINGLE ) ;
2012-06-26 06:55:45 +00:00
2012-06-28 18:33:59 +00:00
# ifdef MOUSE_ENABLE
2012-06-26 06:55:45 +00:00
/* Setup Mouse HID Report Endpoint */
2013-02-11 13:56:30 +00:00
ConfigSuccess & = ENDPOINT_CONFIG ( MOUSE_IN_EPNUM , EP_TYPE_INTERRUPT , ENDPOINT_DIR_IN ,
MOUSE_EPSIZE , ENDPOINT_BANK_SINGLE ) ;
2012-06-28 18:33:59 +00:00
# endif
# ifdef EXTRAKEY_ENABLE
/* Setup Extra HID Report Endpoint */
2013-02-11 13:56:30 +00:00
ConfigSuccess & = ENDPOINT_CONFIG ( EXTRAKEY_IN_EPNUM , EP_TYPE_INTERRUPT , ENDPOINT_DIR_IN ,
EXTRAKEY_EPSIZE , ENDPOINT_BANK_SINGLE ) ;
2012-06-28 18:33:59 +00:00
# endif
2012-06-27 09:31:33 +00:00
2012-07-13 17:47:29 +00:00
# ifdef CONSOLE_ENABLE
2012-06-28 07:51:56 +00:00
/* Setup Console HID Report Endpoints */
2013-02-11 13:56:30 +00:00
ConfigSuccess & = ENDPOINT_CONFIG ( CONSOLE_IN_EPNUM , EP_TYPE_INTERRUPT , ENDPOINT_DIR_IN ,
CONSOLE_EPSIZE , ENDPOINT_BANK_DOUBLE ) ;
ConfigSuccess & = ENDPOINT_CONFIG ( CONSOLE_OUT_EPNUM , EP_TYPE_INTERRUPT , ENDPOINT_DIR_OUT ,
CONSOLE_EPSIZE , ENDPOINT_BANK_SINGLE ) ;
2012-07-13 17:47:29 +00:00
# endif
2012-06-26 06:55:45 +00:00
}
2012-06-28 07:51:56 +00:00
/*
Appendix G : HID Request Support Requirements
The following table enumerates the requests that need to be supported by various types of HID class devices .
Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Boot Mouse Required Optional Optional Optional Required Required
Non - Boot Mouse Required Optional Optional Optional Optional Optional
Boot Keyboard Required Optional Required Required Required Required
Non - Boot Keybrd Required Optional Required Required Optional Optional
Other Device Required Optional Optional Optional Optional Optional
*/
2012-06-26 06:55:45 +00:00
/** Event handler for the USB_ControlRequest event.
* This is fired before passing along unhandled control requests to the library for processing internally .
*/
void EVENT_USB_Device_ControlRequest ( void )
{
2012-06-27 09:31:33 +00:00
uint8_t * ReportData = NULL ;
uint8_t ReportSize = 0 ;
2012-06-26 06:55:45 +00:00
/* Handle HID Class specific requests */
switch ( USB_ControlRequest . bRequest )
{
case HID_REQ_GetReport :
if ( USB_ControlRequest . bmRequestType = = ( REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE ) )
{
Endpoint_ClearSETUP ( ) ;
2012-06-27 09:31:33 +00:00
// Interface
switch ( USB_ControlRequest . wIndex ) {
2012-06-28 03:59:17 +00:00
case KEYBOARD_INTERFACE :
// TODO: test/check
2012-06-26 06:55:45 +00:00
ReportData = ( uint8_t * ) & keyboard_report_sent ;
ReportSize = sizeof ( keyboard_report_sent ) ;
2012-06-27 09:31:33 +00:00
break ;
2012-06-26 06:55:45 +00:00
}
/* Write the report data to the control endpoint */
Endpoint_Write_Control_Stream_LE ( ReportData , ReportSize ) ;
Endpoint_ClearOUT ( ) ;
}
break ;
case HID_REQ_SetReport :
if ( USB_ControlRequest . bmRequestType = = ( REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE ) )
{
2012-06-27 09:31:33 +00:00
// Interface
switch ( USB_ControlRequest . wIndex ) {
2012-06-28 03:59:17 +00:00
case KEYBOARD_INTERFACE :
2012-06-29 07:48:36 +00:00
Endpoint_ClearSETUP ( ) ;
while ( ! ( Endpoint_IsOUTReceived ( ) ) ) {
if ( USB_DeviceState = = DEVICE_STATE_Unattached )
return ;
}
2012-06-27 09:31:33 +00:00
keyboard_led_stats = Endpoint_Read_8 ( ) ;
2012-06-29 07:48:36 +00:00
Endpoint_ClearOUT ( ) ;
Endpoint_ClearStatusStage ( ) ;
2012-06-28 18:33:59 +00:00
break ;
2012-06-27 09:31:33 +00:00
}
2012-06-26 06:55:45 +00:00
2012-06-29 07:48:36 +00:00
}
break ;
case HID_REQ_GetProtocol :
if ( USB_ControlRequest . bmRequestType = = ( REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE ) )
{
Endpoint_ClearSETUP ( ) ;
while ( ! ( Endpoint_IsINReady ( ) ) ) ;
Endpoint_Write_8 ( protocol_report ) ;
Endpoint_ClearIN ( ) ;
Endpoint_ClearStatusStage ( ) ;
}
break ;
case HID_REQ_SetProtocol :
if ( USB_ControlRequest . bmRequestType = = ( REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE ) )
{
Endpoint_ClearSETUP ( ) ;
Endpoint_ClearStatusStage ( ) ;
protocol_report = ( ( USB_ControlRequest . wValue & 0xFF ) ! = 0x00 ) ;
}
break ;
case HID_REQ_SetIdle :
if ( USB_ControlRequest . bmRequestType = = ( REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE ) )
{
Endpoint_ClearSETUP ( ) ;
Endpoint_ClearStatusStage ( ) ;
idle_duration = ( ( USB_ControlRequest . wValue & 0xFF00 ) > > 8 ) ;
}
break ;
case HID_REQ_GetIdle :
if ( USB_ControlRequest . bmRequestType = = ( REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE ) )
{
Endpoint_ClearSETUP ( ) ;
while ( ! ( Endpoint_IsINReady ( ) ) ) ;
Endpoint_Write_8 ( idle_duration ) ;
Endpoint_ClearIN ( ) ;
2012-06-26 06:55:45 +00:00
Endpoint_ClearStatusStage ( ) ;
}
break ;
}
}
/*******************************************************************************
* Host driver
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static uint8_t keyboard_leds ( void )
{
return keyboard_led_stats ;
}
static void send_keyboard ( report_keyboard_t * report )
{
2012-09-06 03:38:39 +00:00
uint8_t timeout = 0 ;
2012-06-26 06:55:45 +00:00
// TODO: handle NKRO report
/* Select the Keyboard Report Endpoint */
Endpoint_SelectEndpoint ( KEYBOARD_IN_EPNUM ) ;
/* Check if Keyboard Endpoint Ready for Read/Write */
2012-09-06 03:38:39 +00:00
while ( - - timeout & & ! Endpoint_IsReadWriteAllowed ( ) ) ;
2012-08-28 11:55:52 +00:00
/* Write Keyboard Report Data */
Endpoint_Write_Stream_LE ( report , sizeof ( report_keyboard_t ) , NULL ) ;
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN ( ) ;
2012-06-26 06:55:45 +00:00
keyboard_report_sent = * report ;
}
static void send_mouse ( report_mouse_t * report )
{
2012-06-28 18:33:59 +00:00
# ifdef MOUSE_ENABLE
2012-09-06 03:38:39 +00:00
uint8_t timeout = 0 ;
2012-06-26 06:55:45 +00:00
/* Select the Mouse Report Endpoint */
Endpoint_SelectEndpoint ( MOUSE_IN_EPNUM ) ;
/* Check if Mouse Endpoint Ready for Read/Write */
2012-09-06 03:38:39 +00:00
while ( - - timeout & & ! Endpoint_IsReadWriteAllowed ( ) ) ;
2012-06-26 06:55:45 +00:00
2012-08-28 11:55:52 +00:00
/* Write Mouse Report Data */
Endpoint_Write_Stream_LE ( report , sizeof ( report_mouse_t ) , NULL ) ;
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN ( ) ;
2012-06-28 18:33:59 +00:00
# endif
2012-06-26 06:55:45 +00:00
}
static void send_system ( uint16_t data )
{
2012-09-06 03:38:39 +00:00
uint8_t timeout = 0 ;
2012-06-29 07:48:36 +00:00
report_extra_t r = {
. report_id = REPORT_ID_SYSTEM ,
. usage = data
} ;
2012-07-13 17:47:29 +00:00
Endpoint_SelectEndpoint ( EXTRAKEY_IN_EPNUM ) ;
2012-09-06 03:38:39 +00:00
while ( - - timeout & & ! Endpoint_IsReadWriteAllowed ( ) ) ;
2012-08-28 11:55:52 +00:00
Endpoint_Write_Stream_LE ( & r , sizeof ( report_extra_t ) , NULL ) ;
Endpoint_ClearIN ( ) ;
2012-06-26 06:55:45 +00:00
}
static void send_consumer ( uint16_t data )
{
2012-09-06 03:38:39 +00:00
uint8_t timeout = 0 ;
2012-06-29 07:48:36 +00:00
report_extra_t r = {
. report_id = REPORT_ID_CONSUMER ,
. usage = data
} ;
2012-07-13 17:47:29 +00:00
Endpoint_SelectEndpoint ( EXTRAKEY_IN_EPNUM ) ;
2012-09-06 03:38:39 +00:00
while ( - - timeout & & ! Endpoint_IsReadWriteAllowed ( ) ) ;
2012-08-28 11:55:52 +00:00
Endpoint_Write_Stream_LE ( & r , sizeof ( report_extra_t ) , NULL ) ;
Endpoint_ClearIN ( ) ;
2012-06-26 06:55:45 +00:00
}
2012-06-27 09:31:33 +00:00
/*******************************************************************************
* sendchar
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-07-13 17:47:29 +00:00
# ifdef CONSOLE_ENABLE
# define SEND_TIMEOUT 5
2012-06-27 09:31:33 +00:00
int8_t sendchar ( uint8_t c )
{
2012-09-06 03:38:39 +00:00
// Not wait once timeouted.
// Because sendchar() is called so many times, waiting each call causes big lag.
static bool timeouted = false ;
2012-06-27 09:31:33 +00:00
if ( USB_DeviceState ! = DEVICE_STATE_Configured )
2012-09-06 03:38:39 +00:00
return - 1 ;
2012-06-27 09:31:33 +00:00
2012-07-13 17:47:29 +00:00
uint8_t ep = Endpoint_GetCurrentEndpoint ( ) ;
2012-06-28 11:15:56 +00:00
Endpoint_SelectEndpoint ( CONSOLE_IN_EPNUM ) ;
2012-09-06 03:38:39 +00:00
if ( ! Endpoint_IsEnabled ( ) | | ! Endpoint_IsConfigured ( ) ) {
Endpoint_SelectEndpoint ( ep ) ;
return - 1 ;
}
if ( timeouted & & ! Endpoint_IsReadWriteAllowed ( ) ) {
Endpoint_SelectEndpoint ( ep ) ;
return - 1 ;
}
timeouted = false ;
2012-06-27 09:31:33 +00:00
2012-07-08 14:57:25 +00:00
uint8_t timeout = SEND_TIMEOUT ;
2012-06-27 09:31:33 +00:00
uint16_t prevFN = USB_Device_GetFrameNumber ( ) ;
2012-07-08 14:57:25 +00:00
while ( ! Endpoint_IsReadWriteAllowed ( ) ) {
2012-06-27 09:31:33 +00:00
switch ( USB_DeviceState ) {
case DEVICE_STATE_Unattached :
case DEVICE_STATE_Suspended :
return - 1 ;
}
2012-07-13 17:47:29 +00:00
if ( Endpoint_IsStalled ( ) ) {
Endpoint_SelectEndpoint ( ep ) ;
2012-06-27 09:31:33 +00:00
return - 1 ;
2012-07-13 17:47:29 +00:00
}
2012-06-27 09:31:33 +00:00
if ( prevFN ! = USB_Device_GetFrameNumber ( ) ) {
2012-07-13 17:47:29 +00:00
if ( ! ( timeout - - ) ) {
2012-09-06 03:38:39 +00:00
timeouted = true ;
2012-07-13 17:47:29 +00:00
Endpoint_SelectEndpoint ( ep ) ;
2012-06-27 09:31:33 +00:00
return - 1 ;
2012-07-13 17:47:29 +00:00
}
2012-06-27 09:31:33 +00:00
prevFN = USB_Device_GetFrameNumber ( ) ;
}
}
Endpoint_Write_8 ( c ) ;
2012-07-08 14:57:25 +00:00
// send when bank is full
2012-06-27 09:31:33 +00:00
if ( ! Endpoint_IsReadWriteAllowed ( ) )
Endpoint_ClearIN ( ) ;
2012-07-13 17:47:29 +00:00
Endpoint_SelectEndpoint ( ep ) ;
return 0 ;
}
# else
int8_t sendchar ( uint8_t c )
{
2012-06-27 09:31:33 +00:00
return 0 ;
}
2012-07-13 17:47:29 +00:00
# endif
2012-08-25 06:49:08 +00:00
/*******************************************************************************
* main
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void SetupHardware ( void )
{
/* Disable watchdog if enabled by bootloader/fuses */
MCUSR & = ~ ( 1 < < WDRF ) ;
wdt_disable ( ) ;
/* Disable clock division */
clock_prescale_set ( clock_div_1 ) ;
// Leonardo needs. Without this USB device is not recognized.
USB_Disable ( ) ;
USB_Init ( ) ;
// for Console_Task
USB_Device_EnableSOFEvents ( ) ;
}
int main ( void ) __attribute__ ( ( weak ) ) ;
int main ( void )
{
SetupHardware ( ) ;
2012-10-26 18:07:37 +00:00
keyboard_init ( ) ;
host_set_driver ( & lufa_driver ) ;
2012-08-25 06:49:08 +00:00
sei ( ) ;
// TODO: can't print here
debug ( " LUFA init \n " ) ;
while ( 1 ) {
2012-10-05 17:23:12 +00:00
keyboard_task ( ) ;
2012-08-25 06:49:08 +00:00
# if !defined(INTERRUPT_CONTROL_ENDPOINT)
USB_USBTask ( ) ;
# endif
}
}