/* * Uses Cypress CY3654D500 development board with an Encore CY7C63743 chip * to emulate a USB keyboard--with one key. Pressing the pushbutton * generates an 's' code sent to the host. This could be set * to act as any key. Key codes may be found in the HID usage * tables document. Currently p53 in v1.11 * * Use this as a simple framework for developing a HID application * using the Byte Craft compiler. Ported from original keyboard.c * written for CY7C63512 chip, which has some differences. See changes.txt * * Written to work with the Cypress application board, though * this program only makes use of the switch and the two LEDs. * The temperature sensor must be physically disabled (cut between the * jumper holes at JP2) if you want suspend mode to work right. * * The pushbutton switch is connected between pin 19 (P1.3)and ground, * the ENUM led is connected between pin 7 (P1.4) and ground, and the * ACTIVE LED is connected between pin 8 (P1.6) and ground. * * Use this code as you wish, so long as you abide by the orignal * copyright (shown below). I hope you find this modified version * useful, but I make no guarantees of any kind either. * * ORIGINAL PROGRAM DESCRIPTION and COPYRIGHT BELOW: * ============================================================================= * CYC Code Development System * USB keyboard example * KEYBOARD.C * This code may be adapted for any purpose * when used with the CYC Code Development * System. No warranty is implied or given * as to its usability for any purpose. * * (c) Copyright 2000 Byte Craft Limited * 421 King St.N., Waterloo, ON, Canada, N2J 4E4 * VOICE: 1 (519) 888 6911 * FAX : 1 (519) 746 6751 * email: support@bytecraft.com * * REVISION HISTORY * V0.90b AL 99/06 Initial Version. * V0.91b AL 00/05 ***/ #pragma option f0 #pragma option REGSAVEOFF #pragma option CALLMAP //This must be on to enable tracing with the debugger: #pragma option INSTRUCTIONTIMING #include #include #include const char Endpoint_Descriptor[] = { 0x07, /* descriptor length (7 bytes) */ 0x05, /* descriptor type (ENDPOINT) */ 0x81, /* endpoint address (IN endpoint, endpoint 1) */ 0x03, /* endpoint attributes (interrupt) */ 0x08, 0x00, /* maximum packet size (8 bytes) */ 0x0A /* polling interval (ms) */ }; const char Class_Descriptor[] = { 0x09, /* descriptor size (9 bytes) */ 0x21, /* descriptor type (HID) */ 0x00, 0x01, /* class specification (1.00) */ 0x00, /* hardware target country */ 0x01, /* number of hid class desriptors to follow (1) */ 0x22, /* report descriptor type (2) */ 0x3F, 0x00 }; const char Interface_Descriptor[] = { 0x09, /* length of descriptor (9 bytes) */ 0x04, /* descriptor type (INTERFACE) */ 0x00, /* interface number (0) */ 0x00, /* alternate setting (0) */ 0x01, /* number of endpoints (1) */ 0x03, /* interface class (3..defined by USB spec) */ 0x01, /* interface sub-class (1..defined by USB spec) */ 0x01, /* interface protocol (2..defined by USB spec) */ 0x05 /* interface string index (not supported) */ }; const char config_desc_table[] = { 0x09, /* length of descriptor (9 bytes) */ 0x02, /* descriptor type (CONFIGURATION) */ 0x22, 0x00, /* total length of descriptor (34 bytes) */ 0x01, /* number of interfaces to configure (1) */ 0x01, /* configuration value (1) */ 0x04, /* configuration string index (not supported) */ 0xA0, /* configuration attributes (bus powered, remote wakeup) */ 0x32 /* maximum power (100mA) */ }; const char device_desc_table[] = { 0x12, /* size of descriptor (18 bytes) */ 0x01, /* descriptor type (device descriptor) */ 0x00, 0x01, /* USB spec release (ver 1.0) */ 0x00, /* class code (each interface specifies class information) */ 0x00, /* device sub-class (must be set to 0 because class code is 0) */ 0x00, /* device protocol (no class specific protocol) */ 0x08, /* maximum packet size (8 bytes) */ 0xB4, 0x04, /* vendor ID (note Cypress vendor ID) */ 0x00, 0x01, /* product ID (Cypress USB keyboard product ID) */ 0x01, 0x00, /* device release number */ 0x01, /* index of manufacturer string (not supported) */ 0x02, /* index of product string (not supported) */ 0x03, /* index of serial number string (not supported) */ 0x01 /* number of configurations (1) */ }; const char hid_report_desc_table[] = { 0x05, 0x01, /* usage page (generic desktop) */ 0x09, 0x06, /* usage (keyboard) */ 0xA1, 0x01, /* collection (application) */ 0x05, 0x07, /* usage page( key codes) */ 0x19, 0xE0, /* usage minimum (224) */ 0x29, 0xE7, /* usage maximum (231) */ 0x15, 0x00, /* logical minimum (0) */ 0x25, 0x01, /* logical maximum (1) */ 0x75, 0x01, /* report size (1 bit) */ 0x95, 0x08, /* report count (8 bytes) */ 0x81, 0x02, /* input (data, variable, absolute) */ 0x95, 0x01, /* report count (1 byte) */ 0x75, 0x08, /* report size (8 bits) */ 0x81, 0x01, /* input (constant) */ 0x95, 0x05, /* report count (5) */ 0x75, 0x01, /* report size (1) */ 0x05, 0x08, /* usage page (LEDs) */ 0x19, 0x01, /* usage minimum (1) */ 0x29, 0x05, /* usage maximum (5) */ 0x91, 0x02, /* output (data, variable, absolute) */ 0x95, 0x01, /* report count (1) */ 0x75, 0x03, /* report size (3) */ 0x91, 0x01, /* output (constant) */ 0x95, 0x06, /* report count (6) */ 0x75, 0x08, /* report size (8) */ 0x15, 0x00, /* logical minimum (0) */ 0x25, 0x65, /* logical maximum (101) */ 0x05, 0x07, /* usage page (key codes) */ 0x19, 0x00, /* usage minimum (0) */ 0x29, 0x65, /* usage maximum (101) */ 0x81, 0x00, /* input (data, array) */ 0xC0 /* end collection */ }; /* These tables are the mechanism used to return status information to the * host. The status can be either device, interface, or endpoint. ***/ const char get_dev_status_table[] = { 0x00, 0x00, /* remote wakeup disabled, bus powered */ 0x02, 0x00 /* remote wakeup enabled, bus powered */ }; const char get_interface_status_table[] = { 0x00, 0x00 /* always return both bytes zero */ }; const char get_endpoint_status_table[] = { 0x00, 0x00, /* not stalled */ 0x01, 0x00 /* stalled */ }; /* String Descriptors */ const char USBStringLanguageDescription[] = { 0x04, /* Length */ 0x03, /* Type (3=string) */ 0x09, /* Language: English */ 0x04 /* Sub-language: Default */ }; const char USBStringDescription1[] = { 0x10,0x03,'C',0,'y',0,'p',0,'r',0,'e',0,'s',0,'s',0 }; const char USBStringDescription2[] = { 0x2A, 0x03, 'C',0,'y',0,'p',0,'r',0,'e',0,'s',0,'s',0,' ',0, 'U',0,'S',0,'B',0,' ',0,'K',0,'e',0,'y',0,'b',0, 'o',0,'a',0,'r',0,'d',0 }; const char USBStringDescription3[] = { 0x10,0x03,'6',0,'5',0,'4',0,'3',0,'2',0,'1',0,'0',0 }; /* is a serial number is used this number must be unique */ /* for every device or else it may not enumerate properly */ const char USBStringDescription4[] = { 0x1A, 0x03, 'H',0,'I',0,'D',0,' ',0,'K',0,'e',0,'y',0,'b', 0,'o',0,'a',0,'r',0,'d',0 }; const char USBStringDescription5[] = { 0x28, 0x03, 'E',0,'n',0,'d',0,'P',0,'o',0,'i',0,'n',0,'t',0,'1',0,' ',0,'I',0, 'n',0,'t',0,'e',0,'r',0,'r',0,'u',0,'p',0,'t',0 }; #define ACTIVE_LED_OFF() port_set_bit_PORT1(6) #define ACTIVE_LED_ON() port_clear_bit_PORT1(6) #define ENUM_LED_ON() port_clear_bit_PORT1(4) #define ENUM_LED_OFF() port_set_bit_PORT1(4) /* constant declarationsfrom USB Spec v1.0 from page 175 * standard request codes ***/ #define USB_GET_STATUS 0x00 #define USB_CLEAR_FEATURE 0x01 #define USB_SET_FEATURE 0x03 #define USB_SET_ADDRESS 0x05 #define USB_GET_DESCRIPTOR 0x06 #define USB_SET_DESCRIPTOR 0x07 #define USB_GET_CONFIGURATION 0x08 #define USB_SET_CONFIGURATION 0x09 #define USB_GET_INTERFACE 0x0A #define USB_SET_INTERFACE 0x0B #define USB_SYNCH_FRAME 0x0C #define HOST_TO_DEVICE 0b00000000 #define DEVICE_TO_HOST 0b10000000 #define STANDARD 0b00000000 #define CLASS 0b00100000 #define VENDOR 0b01000000 #define DEVICE 0b00000000 #define INTERFACE 0b00000001 #define ENDPOINT 0b00000010 #define OTHER 0b00000011 /* standard descriptor types */ #define USB_DEVICE 0x01 #define USB_CONFIGURATION 0x02 #define USB_STRING 0x03 #define USB_INTERFACE 0x04 #define USB_ENDPOINT 0x05 /* standard feature selectors */ #define USB_ENDPOINT_STALL 0x00 /* recipient endpoint */ #define USB_DEVICE_REMOTE_WAKEUP 0x01 /* recipient device */ /* from HID Class v1.0 Draft #4 * class specific descriptor types from section 7.1 Standard R ests ***/ #define USB_HID 0x21 #define USB_REPORT 0x22 #define USB_PHYSICAL 0x23 /* class specific request codes from section 7.2 Class Specific R ests */ #define USB_GET_REPORT 0x01 #define USB_GET_IDLE 0x02 #define USB_GET_PROTOCOL 0x03 #define USB_SET_REPORT 0x09 #define USB_SET_IDLE 0x0A #define USB_SET_PROTOCOL 0x0B #define DISABLE_REMOTE_WAKEUP 0x00 /* bit[1] = 0 */ #define ENABLE_REMOTE_WAKEUP 0x02 /* bit[1] = 1 */ /* Debounce FIFO * Size of debounce fifo depends on debounce time of switch * Each debounce fifo location is updated on a 12 ms interval. This * example uses 4 bytes for the fifo, making a 48 ms switch debounce time. ***/ #define DEB_LO_ADDR 0x00 /* start of fifo offset */ #define DEB_HI_ADDR 0x06 /* end of fifo + 1 offset for overflow test */ /* Task Scheduler (in One Millisecond interrupt routine) */ #define SCAN_TIME 0x03 /* scan time test value */ #define DEB_TIME 0x0C /* debounce time test value (12 ms) */ #define CONFIGURED 0x01 /* configuration status values */ #define UNCONFIGURED 0x00 #define BOOT_PROTOCOL 0x00 /* protocol status values */ #define REPORT_PROTOCOL 0x01 #define DEBOUNCE_RELEASE_TIME 0x01 /* set debounce time for 1*4ms= 4ms */ #define DEBOUNCE_PRESS_TIME 0x03 /* set debounce time for 3*4ms= 12ms */ #define COUNT_MASK 0x0F /* count[3:0] bits */ #define DATAVALID 0x40 /* data valid (OUT and SETUP) */ #define DATATOGGLE 0x80 /* Data 0/1 bit */ #define NORMAL PORT0_OPEN_IFALL | PORT1_OPEN_IFALL | PORT2_RESISTIVE | PORT3_OPEN_IFALL #define P3_KEY_MASK 0xF0 /* bits[7:4] */ #define P3_LED_MASK 0x0F /* bits[3:0] */ #define NUM_LOCK_LED 0x01 /* bit[0] */ #define CAPS_LOCK_LED 0x02 /* bit[1] */ #define SCROLL_LOCK_LED 0x04 /* bit[2] */ #define ADDRESS_MASK 0x7F /* 7 bits of device address */ #define ADDRESS_ENABLE_BIT 0x80 /* enable the device address */ #define MOD_LEFT_CTRL 0xE0 #define MOD_LEFT_SFT 0xE1 #define MOD_LEFT_ALT 0xE2 #define MOD_LEFT_GUI 0xE3 #define MOD_RIGHT_CTRL 0xE4 #define MOD_RIGHT_SFT 0xE5 #define MOD_RIGHT_ALT 0xE6 #define MOD_RIGHT_GUI 0xE7 void read_key(void); void start_scan(void); void sendkey(char code); void send_error_report(void); void send_keyboard_report(void); void prepare_error_code(void); void copy_report_buffer_to_EP1(void); void enable_EP1_transmission(void); void USB_init(void); void USB_no_data_control(void); void USB_control_read(void); void USB_control_write(void); void USB_send_buffer(void); void USB_set_ep0_mode(char); void USB_stage_one(void); void USB_send_stall(void); void delay_loop(char); /* Variables to support the USB specification. */ char remote_wakeup_status; /* remote wakeup request */ /* zero is disabled */ /* two is enabled */ char configuration_status; /* configuration status */ /* zero is unconfigured */ /* one is configured */ char endpoint_stall_status; /* zero is not stalled */ /* one is stalled */ char protocol_status; /* zero is boot protocol */ /* one is report protocol */ char far * USB_send_buffer_ptr; char idle_period; char prev_idle_period; char new_idle_period; char new_idle_flag; char idle_period_counter; char four_ms_counter; char debounce_counter; char suspend_counter; int16 ms_time; char keystate; char keychanged; /* support the scan matrix */ char data_start; char data_count; char byte_count; char wakeup_counter; /* used to count 10ms wakeup signal */ char wakeup_flag; /* indicates wakeup is in process */ /* application support */ char task; /* # of task to be executed by main. */ /* scheduled by 1 ms timer */ char schedule; /* task schedule counter */ char tx_required; /* indicates a key(s) changed state */ /* therefore a report is required */ /* current keyswitch state in RAM is 46h to 66h (20 columns) */ char image[20]; char changes; /* keypress changes in a column */ char data_ok; /* flag to indicate validity of received data */ char down_up; /* 0x00: key went up, FFh: key went down */ char premature_setup; char dbfifo[DEB_HI_ADDR]; /* debounce FIFO */ char db_ca[DEB_HI_ADDR]; char report_buffer[8]; /* duplicate input report buffer */ /* last_mod */ /* reserved_byte */ /* last_key1 */ /* last_key2 */ /* last_key3 */ /* last_key4 */ /* last_key5 */ /* last_key6 */ char error_code_buffer[8]; /* error_mod */ /* error_reserved */ /* error_key1 */ /* error_key2 */ /* error_key3 */ /* error_key4 */ /* error_key5 */ /* error_key6 */ char phantom_key_flag; /* flag indicates phantom key situation */ char key_count; /* indicates number of keys pressed */ char kb_error_sent; /* indicates keyboard error sent */ char temp; char last_mod; char ep0mode; unsigned int bit_mask; #pragma vector RESERVED @ 0x000e; #pragma vector RESERVED @ 0x0010; #pragma vector RESERVED @ 0x0012; //#pragma vector RESERVED @ 0x0018; void RESERVED(void) {} void MICROSECONDx128_ISR(void) { // HALT(); } void USB_EP2_ISR(void) { // HALT(); } void DAC_ISR(void) { // HALT(); } /* When the part detects a single-ended zero from the upstream port, * an interrupt occurs that wakes up the CPU from suspend mode and * transfers control to this interrupt service routine. * * clears watchdog timer * clears USB device address register * * The USB Bus Reset interrupt service routine prepares for enumeration. ***/ void USB_BUS_RESET_ISR(void) { PUSHA(); PUSHX(); RESET_COP(); PROCESSOR_STATUS.USB_RESET = 0; GLOBAL_INTERRUPT = MILLISECOND_ENABLE | USB_RESET_ENABLE; ENDPOINT_INTERRUPT = EPA0_ENABLE; /* enable Endpoint 0 interrupt */ AC = EP_A0_MODE; EP_A0_MODE = USB_MODE_IGNORE_IN_OUT; /* accept setup */ USB_DEVICE_A=(1<= (idle_period_counter+2)) ) idle_period = new_idle_period; else new_idle_flag=1; } } void SetProtocol(void) { AC=ENDPOINT_A0_FIFO[USB_wValue]; if( (ENDPOINT_A0_FIFO[USB_wValue] != BOOT_PROTOCOL) && (ENDPOINT_A0_FIFO[USB_wValue] != REPORT_PROTOCOL) ) USB_send_stall(); else { protocol_status = ENDPOINT_A0_FIFO[USB_wValue]; USB_no_data_control(); } } void GetReport(void) { data_count = 8; if (kb_error_sent == 0) USB_send_buffer_ptr = error_code_buffer; else USB_send_buffer_ptr = report_buffer; USB_control_read(); } void GetIdle(void) { data_count = sizeof(new_idle_period); USB_send_buffer_ptr=&new_idle_period; USB_control_read(); } void GetProtocol(void) { data_count = sizeof(protocol_status); /* send one byte */ USB_send_buffer_ptr=&protocol_status; USB_control_read(); } enum request_function_index { USB_send_stall_index, ClearRemoteWakeup_index, SetRemoteWakeup_index, SetAddress_index, SetConfiguration_index, ClearEndpointStall_index, SetEndpointStall_index, GetDeviceStatus_index, GetDescriptor_index, GetConfiguration_index, GetInterfaceStatus_index, GetEndpointStatus_index, SetReport_index, SetIdle_index, SetProtocol_index, GetReport_index, GetIdle_index, GetProtocol_index }; enum request_function_index function_index; char far * table_ptr; const char newtable[] = { /*----------bmRequestType--------------*/ /*------bRequest------*/ /*DIRECTION TYPE RECIPIENT*/ /*#####################################*/ HOST_TO_DEVICE | STANDARD | DEVICE , USB_CLEAR_FEATURE , ClearRemoteWakeup_index , /* 00 01 */ HOST_TO_DEVICE | STANDARD | DEVICE , USB_SET_FEATURE , SetRemoteWakeup_index , /* 00 03 */ HOST_TO_DEVICE | STANDARD | DEVICE , USB_SET_ADDRESS , SetAddress_index , /* 00 05 */ HOST_TO_DEVICE | STANDARD | DEVICE , USB_SET_CONFIGURATION, SetConfiguration_index , /* 00 09 */ HOST_TO_DEVICE | STANDARD | ENDPOINT , USB_CLEAR_FEATURE , ClearEndpointStall_index, /* 02 01 */ HOST_TO_DEVICE | STANDARD | ENDPOINT , USB_SET_FEATURE , SetEndpointStall_index , /* 02 03 */ DEVICE_TO_HOST | STANDARD | DEVICE , USB_GET_STATUS , GetDeviceStatus_index , /* 80 00 */ DEVICE_TO_HOST | STANDARD | DEVICE , USB_GET_DESCRIPTOR , GetDescriptor_index , /* 80 06 */ DEVICE_TO_HOST | STANDARD | DEVICE , USB_GET_CONFIGURATION, GetConfiguration_index , /* 80 08 */ DEVICE_TO_HOST | STANDARD | INTERFACE , USB_GET_STATUS , GetInterfaceStatus_index, /* 81 00 */ DEVICE_TO_HOST | STANDARD | INTERFACE , USB_GET_DESCRIPTOR , GetDescriptor_index , /* 81 06 */ DEVICE_TO_HOST | STANDARD | ENDPOINT , USB_GET_STATUS , GetEndpointStatus_index , /* 82 00 */ DEVICE_TO_HOST | STANDARD | ENDPOINT , USB_GET_DESCRIPTOR , GetDescriptor_index , /* 82 06 */ HOST_TO_DEVICE | CLASS | INTERFACE , USB_SET_REPORT , SetReport_index , /* 21 09 */ HOST_TO_DEVICE | CLASS | INTERFACE , USB_SET_IDLE , SetIdle_index , /* 21 0A */ HOST_TO_DEVICE | CLASS | INTERFACE , USB_SET_PROTOCOL , SetProtocol_index , /* 21 0B */ HOST_TO_DEVICE | CLASS | ENDPOINT , USB_SET_REPORT , SetReport_index , /* 22 09 */ HOST_TO_DEVICE | CLASS | ENDPOINT , USB_SET_IDLE , SetIdle_index , /* 22 0A */ HOST_TO_DEVICE | CLASS | ENDPOINT , USB_SET_PROTOCOL , SetProtocol_index , /* 22 0B */ DEVICE_TO_HOST | CLASS | INTERFACE , USB_GET_REPORT , GetReport_index , /* A1 01 */ DEVICE_TO_HOST | CLASS | INTERFACE , USB_GET_IDLE , GetIdle_index , /* A1 02 */ DEVICE_TO_HOST | CLASS | INTERFACE , USB_GET_PROTOCOL , GetProtocol_index /* A1 03 */ }; const void (* request_func_table[])(void)= { USB_send_stall, ClearRemoteWakeup, SetRemoteWakeup, SetAddress, SetConfiguration, ClearEndpointStall, SetEndpointStall, GetDeviceStatus, GetDescriptor, GetConfiguration, GetInterfaceStatus, GetEndpointStatus, SetReport, SetIdle, SetProtocol, GetReport, GetIdle, GetProtocol }; void USB_stage_one(void) { table_ptr = newtable; function_index = USB_send_stall_index; do { if( *table_ptr == ENDPOINT_A0_FIFO[USB_bmRequestType] ) { if( *(table_ptr+1) == ENDPOINT_A0_FIFO[USB_bRequest] ) function_index = *(table_ptr+2); } table_ptr += 3; } while( table_ptr < (newtable + sizeof(newtable)) ); (*request_func_table[function_index])(); }