├── GenericTypeDefs.h ├── GenericMacros.h ├── LwUSBhost.tagsrc ├── USARTio.h ├── cli.h ├── README ├── HID.h ├── LwUSBhost.mcp ├── project_config.h ├── cli_constants.h ├── USARTio.c ├── LwUSBhost.c ├── MAX3421E.h ├── usb_ch9.h ├── HID.c ├── MAX3421E.c ├── USB.h ├── transfer.h ├── transfer.c └── cli.c /GenericTypeDefs.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felis/lightweight-usb-host/HEAD/GenericTypeDefs.h -------------------------------------------------------------------------------- /GenericMacros.h: -------------------------------------------------------------------------------- 1 | /* Generic macros */ 2 | 3 | /* Word <> two chars. Works both ways */ 4 | #define LOBYTE(x) ((char*)(&(x)))[0] 5 | #define HIBYTE(x) ((char*)(&(x)))[1] 6 | 7 | 8 | /* Bit set/clear */ 9 | #define bitset(var, bitno) ((var) |= 1 << (bitno)) 10 | #define bitclr(var, bitno) ((var) &= ~(1 << (bitno))) -------------------------------------------------------------------------------- /LwUSBhost.tagsrc: -------------------------------------------------------------------------------- 1 | C:\work\projects\Lightweight_USB\PIC18F26K20\LwUSBhost.c 2 | C:\work\projects\Lightweight_USB\PIC18F26K20\USARTio.c 3 | C:\work\projects\Lightweight_USB\PIC18F26K20\cli.c 4 | C:\work\projects\Lightweight_USB\PIC18F26K20\MAX3421E.c 5 | C:\work\projects\Lightweight_USB\PIC18F26K20\transfer.c 6 | C:\work\projects\Lightweight_USB\PIC18F26K20\HID.c 7 | -------------------------------------------------------------------------------- /USARTio.h: -------------------------------------------------------------------------------- 1 | /* USART support header file */ 2 | /* accompanies USARTio.c */ 3 | 4 | #ifndef _USARTio_h_ 5 | #define _USARTio_h_ 6 | 7 | /* USARTio.c function declarations */ 8 | void USART_init( void ); 9 | BYTE recvchar( void ); 10 | BYTE sendchar( BYTE data ); 11 | BOOL CharInQueue( void ); 12 | void send_string( const rom char *str_ptr ); 13 | void send_ram_string (char *str_ptr); 14 | void send_hexbyte( BYTE data ); 15 | void send_decword ( WORD number ); 16 | void send_dotted_decimal( char *octet ); 17 | 18 | #endif // _USARTIO_h_ 19 | -------------------------------------------------------------------------------- /cli.h: -------------------------------------------------------------------------------- 1 | /* cli.c support file */ 2 | 3 | #ifndef _cli_h_ 4 | #define _cli_h_ 5 | 6 | //#include "GenericTypeDefs.h" 7 | 8 | /* Function declarations */ 9 | 10 | void CLI_init( void ); 11 | void CLI_Task( void ); 12 | void CLI_main_menu( void ); 13 | void CLI_show_menu( void ); 14 | void CLI_set_menu( void ); 15 | void CLI_usbq_menu( void ); 16 | void CLI_usbt_menu( void ); 17 | void CLI_util_menu( void ); 18 | /**/ 19 | void printDevDescr( BYTE addr ); 20 | void printConfDescr( BYTE addr, BYTE conf ); 21 | void printIntrDescr( char *byteptr ); 22 | void printEpDescr( char *byteptr ); 23 | void printHIDdescr( char *byteptr ); 24 | void testMouse ( BYTE addr ); 25 | void testKbd( BYTE addr ); 26 | // prevCodeComp( BYTE data, BOOT_KBD_REPORT* buf ); 27 | void SPI_test( void ); 28 | 29 | #endif // _cli_h_ 30 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is a project directory of Lightweight USB host for Microchip PIC18 and Maxim MAX3421E USB Host controller. 2 | This is a migration from FreeRTOS implementation, which I decided to stop developing because the end product will not fit into PIC18. 3 | Therefore, you will find fragments of strange code every now and then. 4 | 5 | The code is compiled using Microchip C18 compiler in MPLAB. MPLAB project file is provided but not guaranteed to work on your system 6 | due to absolute path issue. You can manually edit the .mcp file or make your own. The project uses standard linker script and headers. 7 | 8 | In addition, logic analyzer trace is provided in LPF file. Too see the trace you will need to download Logicport software from Intronix, 9 | http://www.pctestinstruments.com/downloads.htm 10 | 11 | For hardware implementation information go to http://www.circuitsathome.com 12 | 13 | -------------------------------------------------------------------------------- /HID.h: -------------------------------------------------------------------------------- 1 | /* HID support header */ 2 | 3 | #ifndef _HID_h_ 4 | #define _HID_h 5 | 6 | /* HID device structure */ 7 | typedef struct { 8 | BYTE addr; 9 | BYTE interface; 10 | } HID_DEVICE; 11 | /* Boot mouse report 8 bytes */ 12 | typedef struct { 13 | // struct { 14 | // unsigned one:1; 15 | // unsigned two:1; 16 | // unsigned three:1; 17 | // unsigned :5; 18 | // } button; 19 | BYTE button; 20 | BYTE Xdispl; 21 | BYTE Ydispl; 22 | BYTE bytes3to7[ 5 ] ; //optional bytes 23 | } BOOT_MOUSE_REPORT; 24 | /* boot keyboard report 8 bytes */ 25 | typedef struct { 26 | // BYTE mod; 27 | struct { 28 | unsigned LCtrl:1; 29 | unsigned LShift:1; 30 | unsigned LAlt:1; 31 | unsigned LWin:1; 32 | /**/ 33 | unsigned RCtrl:1; 34 | unsigned RShift:1; 35 | unsigned RAlt:1; 36 | unsigned RWin:1; 37 | } mod; 38 | BYTE reserved; 39 | BYTE keycode[ 6 ]; 40 | } BOOT_KBD_REPORT; 41 | 42 | 43 | /* Function prototypes */ 44 | BOOL HIDMProbe( BYTE address, DWORD flags ); 45 | BOOL HIDKProbe( BYTE address, DWORD flags ); 46 | void HID_init( void ); 47 | BYTE mousePoll( BOOT_MOUSE_REPORT* buf ); 48 | BYTE kbdPoll( BOOT_KBD_REPORT* buf ); 49 | BOOL HIDMEventHandler( BYTE addr, BYTE event, void *data, DWORD size ); 50 | BOOL HIDKEventHandler( BYTE addr, BYTE event, void *data, DWORD size ); 51 | #endif // _HID_h_ -------------------------------------------------------------------------------- /LwUSBhost.mcp: -------------------------------------------------------------------------------- 1 | [HEADER] 2 | magic_cookie={66E99B07-E706-4689-9E80-9B2582898A13} 3 | file_version=1.0 4 | device=PIC18F26K20 5 | [PATH_INFO] 6 | BuildDirPolicy=BuildDirIsProjectDir 7 | dir_src= 8 | dir_bin= 9 | dir_tmp= 10 | dir_sin= 11 | dir_inc= 12 | dir_lib=C:\MCC18\lib 13 | dir_lkr= 14 | [CAT_FILTERS] 15 | filter_src=*.asm;*.c 16 | filter_inc=*.h;*.inc 17 | filter_obj=*.o 18 | filter_lib=*.lib 19 | filter_lkr=*.lkr 20 | [CAT_SUBFOLDERS] 21 | subfolder_src= 22 | subfolder_inc= 23 | subfolder_obj= 24 | subfolder_lib= 25 | subfolder_lkr= 26 | [FILE_SUBFOLDERS] 27 | file_000=. 28 | file_001=. 29 | file_002=. 30 | file_003=. 31 | file_004=. 32 | file_005=. 33 | file_006=. 34 | [GENERATED_FILES] 35 | file_000=no 36 | file_001=no 37 | file_002=no 38 | file_003=no 39 | file_004=no 40 | file_005=no 41 | file_006=no 42 | [OTHER_FILES] 43 | file_000=no 44 | file_001=no 45 | file_002=no 46 | file_003=no 47 | file_004=no 48 | file_005=no 49 | file_006=no 50 | [FILE_INFO] 51 | file_000=LwUSBhost.c 52 | file_001=USARTio.c 53 | file_002=cli.c 54 | file_003=MAX3421E.c 55 | file_004=transfer.c 56 | file_005=HID.c 57 | file_006=C:\MCC18\lkr\18f26k20i.lkr 58 | [SUITE_INFO] 59 | suite_guid={5B7D72DD-9861-47BD-9F60-2BE967BF8416} 60 | suite_state= 61 | [TOOL_SETTINGS] 62 | TS{DD2213A8-6310-47B1-8376-9430CDFC013F}= 63 | TS{BFD27FBA-4A02-4C0E-A5E5-B812F3E7707C}=/m"$(BINDIR_)$(TARGETBASE).map" /o"$(BINDIR_)$(TARGETBASE).cof" 64 | TS{C2AF05E7-1416-4625-923D-E114DB6E2B96}=-k -Ou- -Ot- -Ob- -Op- -Or- -Od- -Opa- 65 | TS{ADE93A55-C7C7-4D4D-A4BA-59305F7D0391}= 66 | [INSTRUMENTED_TRACE] 67 | enable=0 68 | transport=0 69 | format=0 70 | [CUSTOM_BUILD] 71 | Pre-Build= 72 | Pre-BuildEnabled=1 73 | Post-Build= 74 | Post-BuildEnabled=1 75 | -------------------------------------------------------------------------------- /project_config.h: -------------------------------------------------------------------------------- 1 | /* Project name project configuration file */ 2 | 3 | #ifndef _project_config_h_ 4 | #define _project_config_h_ 5 | 6 | /* define MCU family and configuration fuses if any */ 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | #include "GenericMacros.h" 13 | #include "GenericTypeDefs.h" 14 | #include "USARTio.h" 15 | #include "MAX3421E.h" 16 | #include "cli.h" 17 | #include "USB.h" 18 | #include "usb_ch9.h" 19 | #include "transfer.h" 20 | #include "HID.h" 21 | 22 | 23 | //#define CLOCK 3 //milliseconds 24 | 25 | /* PIC pin functional assignments */ 26 | 27 | #define MAX3421E_SS PORTBbits.RB0 //output. SS low selects 28 | #define MAX3421E_INT PORTBbits.RB1 //input 29 | #define MAX3421E_INT_TR TRISBbits.TRISB1 30 | #define MAX3421E_GPX PORTBbits.RB2 //input 31 | #define MAX3421E_GPX_TR TRISBbits.TRISB2 32 | #define MAX3421E_RESET PORTBbits.RB3 //output. RESET low resets 33 | 34 | #define Select_MAX3421E MAX3421E_SS = 0 35 | #define Deselect_MAX3421E MAX3421E_SS = 1 36 | 37 | #define BPNT_0 PORTBbits.RB4 38 | #define set_BPNT_0 BPNT_0 = 1; 39 | #define clr_BPNT_0 BPNT_0 = 0; 40 | #define tgl_BPNT_0 set_BPNT_0; clr_BPNT_0 41 | 42 | /* Async serial settings */ 43 | /* USART transmit and receive buffer sizes */ 44 | /* must be a power of 2 */ 45 | #define USART_TX_BUFSIZE 16 46 | #define USART_TX_BUF_MASK ( USART_TX_BUFSIZE - 1 ) 47 | #if (USART_TX_BUFSIZE & USART_TX_BUF_MASK) 48 | #error USART Tx buffer size is not a power of 2 49 | #endif 50 | 51 | #define USART_RX_BUFSIZE 16 52 | #define USART_RX_BUF_MASK ( USART_RX_BUFSIZE - 1 ) 53 | #if (USART_RX_BUFSIZE & USART_RX_BUF_MASK) 54 | #error USART Rx buffer size is not a power of 2 55 | #endif 56 | 57 | /* USB constants */ 58 | /* time in milliseconds */ 59 | #define USB_SETTLE_TIME 200 //USB settle after reset 60 | #define USB_XFER_TIMEOUT 5000 //USB transfer timeout 61 | 62 | #define USB_NAK_LIMIT 200 63 | #define USB_RETRY_LIMIT 3 64 | 65 | 66 | 67 | #endif // _project_config_h -------------------------------------------------------------------------------- /cli_constants.h: -------------------------------------------------------------------------------- 1 | /* strings and other constants for cli.c module */ 2 | 3 | #ifndef _cli_constants_h_ 4 | #define _cli_constants_h_ 5 | 6 | const rom char *const rom cli_banner = 7 | "\r\nCircuits At Home" 8 | "\r\n\nLightweight USB Host serial console\r\n" 9 | "\r\n"; 10 | 11 | const rom char *const rom cli_root_menu_help = 12 | "\r\n1 - Show device parameters\r\n" 13 | "2 - Set device parameters\r\n" 14 | "3 - USB queries\r\n" 15 | "4 - USB transfers\r\n" 16 | "5 - Utilities\r\n"; 17 | 18 | const rom char *const rom cli_show_menu_help = 19 | "\r\n1 - print MAX3421E Registers\r\n" 20 | "2 - Show USB task state\r\n" 21 | "3 - Show devices\r\n"; 22 | 23 | const rom char *const rom cli_set_menu_help = 24 | "\r\n1 - Reset MAX3421E\r\n" 25 | "2 - turn Vbus on\r\n" 26 | "3 - turn Vbus off\r\n" 27 | "4 - set HID boot protocol\r\n" 28 | "5 - set HID report protocol\r\n"; 29 | 30 | const rom char *const rom cli_usbq_menu_help = 31 | "\r\n1 - print device descriptor\r\n" 32 | "2 - print configuration\r\n" 33 | "3 - Item 3\r\n"; 34 | 35 | const rom char *const rom cli_usbt_menu_help = 36 | "\r\n1 - test mouse communication\r\n" 37 | "2 - test keyboard communication\r\n" 38 | "3 - Item 3\r\n"; 39 | 40 | const rom char *const rom cli_util_menu_help = 41 | "\r\n1 - Test SPI transfers\r\n" 42 | "2 - Util menu item 2\r\n" 43 | "3 - Util menu item 3\r\n"; 44 | 45 | const rom char *const rom crlf = "\r\n"; 46 | const rom char *const rom angle = ">"; 47 | const rom char *const rom cli_prompt_main = "\r\n(main).Press `?` for help>"; 48 | const rom char *const rom cli_prompt_show = "\r\n(show)>"; 49 | const rom char *const rom cli_prompt_set = "\r\n(set).Press `?` for help>"; 50 | const rom char *const rom cli_prompt_usbq = "\r\n(usbq).Press `?` for help>"; 51 | const rom char *const rom cli_prompt_usbt = "\r\n(usbt)>"; 52 | const rom char *const rom cli_prompt_util = "\r\n(util)>"; 53 | 54 | const rom char *const rom esc_prev_lvl = " - previous level\r\n"; 55 | const rom char *const rom cli_invalid_key = "\r\nInvalid key pressed\r\n"; 56 | 57 | /* Regiser names/numbers for MAX3421E register dump */ 58 | typedef struct { 59 | const rom char *const rom name; 60 | const rom char number; 61 | }REGISTER_OUTPUT_FORMAT; 62 | 63 | const rom REGISTER_OUTPUT_FORMAT register_format[] = { 64 | { "\r\nRCVFIFO:\t", rRCVFIFO }, 65 | { "\r\nSNDFIFO:\t", rSNDFIFO }, 66 | { "\r\nSUDFIFO:\t", rSUDFIFO }, 67 | { "\r\nRCVBC:\t\t", rRCVBC }, 68 | { "\r\nSNDBC:\t\t", rSNDBC }, 69 | { "\r\nUSBIRQ:\t\t", rUSBIRQ }, 70 | { "\r\nUSBIEN:\t\t", rUSBIEN }, 71 | { "\r\nUSBCTL:\t\t", rUSBCTL }, 72 | { "\r\nCPUCTL:\t\t", rCPUCTL }, 73 | { "\r\nPINCTL:\t\t", rPINCTL }, 74 | { "\r\nREVISION:\t", rREVISION }, 75 | { "\r\nIOPINS1:\t", rIOPINS1 }, 76 | { "\r\nIOPINS2:\t", rIOPINS2 }, 77 | { "\r\nGPINIRQ:\t", rGPINIRQ }, 78 | { "\r\nGPINIEN:\t", rGPINIEN }, 79 | { "\r\nGPINPOL:\t", rGPINPOL }, 80 | { "\r\nHIRQ:\t\t", rHIRQ }, 81 | { "\r\nHIEN:\t\t", rHIEN }, 82 | { "\r\nMODE:\t\t", rMODE }, 83 | { "\r\nPERADDR:\t", rPERADDR }, 84 | { "\r\nHCTL:\t\t", rHCTL }, 85 | { "\r\nHXFR:\t\t", rHXFR }, 86 | { "\r\nHRSL:\t\t", rHRSL }, 87 | { NULL, 0 } //end of array 88 | }; 89 | 90 | 91 | const rom char* const rom devclasses[] = { 92 | " Uninitialized", 93 | " HID Keyboard", 94 | " HID Mouse", 95 | " Mass storage" 96 | }; 97 | 98 | 99 | typedef struct _UPTIME_FORMAT { 100 | const rom DWORD divider; 101 | const rom char *const rom name; 102 | }UPTIME_FORMAT; 103 | 104 | const rom UPTIME_FORMAT uptime_format[ 4 ] = { 105 | { 86400000, " days " }, 106 | { 3600000, " hours " }, 107 | { 60000, " minutes " }, 108 | { 1000, " seconds" } 109 | }; 110 | 111 | 112 | #endif //_cli_constants_h_ -------------------------------------------------------------------------------- /USARTio.c: -------------------------------------------------------------------------------- 1 | /* USART IO Functions */ 2 | 3 | #define _USARTIO_C_ 4 | 5 | #include "project_config.h" 6 | 7 | extern volatile BYTE USART_Tx_buf [ USART_RX_BUFSIZE ]; 8 | extern volatile BYTE USART_Tx_head; 9 | extern volatile BYTE USART_Tx_tail; 10 | 11 | extern volatile BYTE USART_Rx_buf [ USART_RX_BUFSIZE ]; 12 | extern volatile BYTE USART_Rx_head; 13 | extern volatile BYTE USART_Rx_tail; 14 | 15 | /* Init USART Function for PIC18s with 1 USART */ 16 | /* 96000 8N1:-) @64MHz* - SPBRG 103 */ 17 | 18 | void USART_init(void) 19 | { 20 | SPBRG = 103; //baud rate divisor 9600@64MHz low speed 21 | //SPBRG = 25; //baud rate generator 9600@16MHz 22 | TRISCbits.TRISC7 = 1; //receive pin 23 | TRISCbits.TRISC6 = 0; //transmit pin 24 | 25 | RCSTA = 0x80; //enable serial port and serial port pins 26 | IPR1bits.RCIP = 0; //receive interrupt = low priority 27 | IPR1bits.TXIP = 0; //transmit interrupt = low priority 28 | PIE1bits.RCIE = 1; //enable receive interrupt 29 | RCSTAbits.CREN = 1; //enable USART1 receiver 30 | PIE1bits.TXIE = 0; //disable USART1 transmit interrupt 31 | TXSTAbits.TXEN = 1; //transmitter enabled 32 | } 33 | 34 | /* get character */ 35 | BYTE recvchar(void) 36 | { 37 | BYTE tmptail; 38 | 39 | while ( USART_Rx_head == USART_Rx_tail ); // wait for incoming data 40 | tmptail = ( USART_Rx_tail + 1 ) & USART_RX_BUF_MASK; // calculate buffer index 41 | USART_Rx_tail = tmptail; // store new index 42 | 43 | return USART_Rx_buf[tmptail]; // return data 44 | } 45 | 46 | /* send character */ 47 | /* blocks program execution while txbuf is full */ 48 | /* use with caution */ 49 | BYTE sendchar(BYTE data) 50 | { 51 | BYTE tmphead; 52 | tmphead = ( USART_Tx_head + 1 ) & USART_TX_BUF_MASK; // calculate buffer index 53 | while ( tmphead == USART_Tx_tail ); // wait for free space in buffer 54 | USART_Tx_buf[tmphead] = data; // store data in buffer 55 | USART_Tx_head = tmphead; // store new index 56 | PIE1bits.TXIE = 1; // enable TX interrupt 57 | return data; 58 | } 59 | 60 | /* Check for char in Rx queue */ 61 | BOOL CharInQueue(void) 62 | { 63 | return(USART_Rx_head != USART_Rx_tail); 64 | } 65 | 66 | /* sends a NULL-terminated ROM string to sendchar() */ 67 | void send_string (const rom char *str_ptr) 68 | { 69 | while (*str_ptr) { 70 | sendchar(*str_ptr); 71 | str_ptr++; 72 | } 73 | } 74 | 75 | /* sends a NULL-terminated RAM string to sendchar() */ 76 | void send_ram_string (char *str_ptr) 77 | { 78 | while (*str_ptr) { 79 | sendchar(*str_ptr); 80 | str_ptr++; 81 | } 82 | } 83 | 84 | /* sending 2 ASCII symbols representing input byte in hex */ 85 | void send_hexbyte ( BYTE data ) 86 | { 87 | 88 | BYTE temp = data>>4; //prepare first output character 89 | 90 | if ( temp > 9 ) temp+=7; //jump to letters in ASCII table 91 | sendchar ( temp + 0x30 ); 92 | 93 | data = data & 0x0f; // mask 4 high bits 94 | if ( data > 9 ) data+=7; 95 | sendchar ( data + 0x30 ); 96 | } 97 | /* itoa variation for positive 16-bit integers */ 98 | void send_decword ( WORD number ) 99 | { 100 | BYTE buf[6], next = 0; 101 | WORD k, r, flag = 0; 102 | 103 | if( number == 0 ) { 104 | buf[ next ] = '0'; 105 | next++; 106 | } 107 | else { 108 | k = 10000; 109 | while( k > 0 ) { 110 | r = number / k; 111 | if( flag || r > 0 ) { 112 | buf[ next ] = '0' + r; 113 | next++; 114 | flag = 1; 115 | } 116 | number -= r * k; 117 | k = k / 10; 118 | } 119 | } 120 | buf[ next ] = 0; //add NULL termination 121 | send_ram_string( buf ); 122 | } 123 | 124 | /* outputs 4 consecutive bytes in dotted-decimal format */ 125 | void send_dotted_decimal( char *octet_ptr ) 126 | { 127 | BYTE i; 128 | 129 | for( i = 0; i < 4; i++) { 130 | send_decword(( WORD ) *octet_ptr ); 131 | octet_ptr++; 132 | if( i < 3 ) { //print dots between octets 133 | sendchar( 0x2e ); 134 | } 135 | } 136 | return; 137 | } 138 | 139 | -------------------------------------------------------------------------------- /LwUSBhost.c: -------------------------------------------------------------------------------- 1 | /* pic18f26k20-based MAX3421E based Lightweight USB host */ 2 | 3 | #define _LwUSBhost_c_ 4 | 5 | 6 | #pragma config FOSC = INTIO7, FCMEN = OFF, IESO = OFF, PWRT = OFF, BOREN = OFF, WDTEN = OFF 7 | #pragma config MCLRE = ON, HFOFST = OFF, PBADEN = OFF, STVREN = ON, LVP = OFF, XINST = OFF, DEBUG = ON 8 | 9 | #include "project_config.h" 10 | 11 | /* Global variables */ 12 | volatile DWORD uptime = 0; //system uptime. Gets updated every millisecond 13 | 14 | volatile BYTE USART_Tx_buf [ USART_RX_BUFSIZE ]; 15 | volatile BYTE USART_Tx_head = 0; 16 | volatile BYTE USART_Tx_tail = 0; 17 | volatile BYTE USART_Rx_buf [ USART_RX_BUFSIZE ]; 18 | volatile BYTE USART_Rx_head = 0; 19 | volatile BYTE USART_Rx_tail = 0; 20 | 21 | /* Prototypes */ 22 | void highPriorityISR(void); 23 | void lowPriorityISR(void); 24 | void Board_init( void ); 25 | 26 | /* ISRs */ 27 | #pragma code high_vector=0x08 28 | void interruptAtHighVector(void) 29 | { 30 | _asm GOTO highPriorityISR _endasm 31 | } 32 | #pragma code 33 | #pragma code low_vector=0x18 34 | void interruptAtLowVector(void) 35 | { 36 | _asm GOTO lowPriorityISR _endasm 37 | } 38 | #pragma code 39 | #pragma interruptlow lowPriorityISR 40 | void lowPriorityISR(void) 41 | { 42 | BYTE data,tmphead,tmptail; //USART vars 43 | /* USART handler start */ 44 | if(PIR1bits.RCIF) { 45 | data = RCREG; // read the received data 46 | tmphead = ( USART_Rx_head + 1 ) & USART_RX_BUF_MASK; // calculate buffer index 47 | USART_Rx_head = tmphead; // store new index 48 | if ( tmphead == USART_Rx_tail ) { 49 | // ERROR! Receive buffer overflow 50 | } 51 | USART_Rx_buf[ tmphead ] = data; // store received data in buffer 52 | } 53 | //? need to check for Tx IF 54 | if(TXSTAbits.TRMT) { 55 | // check if all data is transmitted 56 | if ( USART_Tx_head != USART_Tx_tail ) { 57 | tmptail = ( USART_Tx_tail + 1 ) & USART_TX_BUF_MASK; // calculate buffer index 58 | USART_Tx_tail = tmptail; // store new index 59 | TXREG = USART_Tx_buf[ tmptail ]; // start transmition 60 | } 61 | else { 62 | PIE1bits.TXIE = 0; // disable TX interrupt 63 | } 64 | } 65 | /* USART handler end */ 66 | } 67 | 68 | /* Timer1 interrupt handler */ 69 | #pragma interrupt highPriorityISR 70 | void highPriorityISR(void) 71 | { 72 | uptime++; 73 | PIR2bits.CCP2IF = 0; 74 | } 75 | 76 | 77 | 78 | void main ( void ) 79 | { 80 | Board_init(); 81 | USART_init(); 82 | CLI_init(); 83 | SPI_init (SPI_FOSC_4, MODE_00, SMPMID); 84 | MAX3421E_init(); 85 | USB_init(); 86 | while(1) { 87 | CLI_Task(); 88 | MAX3421E_Task(); 89 | USB_Task(); 90 | } 91 | } 92 | 93 | void Board_init( void ) 94 | { 95 | DWORD init_delay; 96 | /* Internal clock is 1MHz by default */ 97 | INTCONbits.GIEH = 0; //disable interrupts 98 | RCONbits.IPEN = 1; //enable interrupt priority 99 | /* Configure all port pins as digital outputs */ 100 | TRISA = 0x00; 101 | LATA = 0x00; 102 | ADCON1 = 0x0f; 103 | PORTA = 0x00; 104 | 105 | TRISB = 0x00; 106 | LATB = 0x00; 107 | PORTB = 0x00; 108 | 109 | TRISC = 0x00; 110 | LATC = 0x00; 111 | PORTC = 0x00; 112 | /* Configure inputs */ 113 | MAX3421E_INT_TR = 1; 114 | MAX3421E_GPX_TR = 1; 115 | /* Initial pin states */ 116 | MAX3421E_SS = 1; 117 | MAX3421E_RESET = 1; //real reset stays low for next 200ms 118 | /* Clock configuration */ 119 | /* Internal High-speed with 4xPLL 64MHz */ 120 | OSCCON |= 0x70; //IRCF = 111 121 | OSCTUNE |= 0x40; //PLL 122 | /* Timer3 configuration */ 123 | TMR3L = 0; 124 | TMR3H = 0; 125 | T3CONbits.T3CCP2 = 1; //CCP2 compare source 126 | T3CON |= 0x00; //1:1 prescale 127 | T3CONbits.TMR3CS = 0; //internal clock 128 | T3CONbits.TMR3ON = 1; //start timer 129 | /* CCP2 configuration. CCP2 reloads Timer3 and generates interrupt */ 130 | CCPR2H = 0x3e; // 16000 cycles, 62.5ns cycle, 1ms between interrupts 131 | CCPR2L = 0x80; 132 | CCP2CON |= 0x0b; //CCP mode 1011, compare triggers special event 133 | PIE2bits.CCP2IE = 1; //enable CCP2 interrupt 134 | IPR2bits.CCP2IP = 1; //set high priority 135 | 136 | INTCONbits.GIEL = 1; //enable low-priority interrupts 137 | INTCONbits.GIEH = 1; //enable all interrupts 138 | init_delay = uptime + 200; 139 | while( init_delay > uptime ); //wait 200ms 140 | } 141 | -------------------------------------------------------------------------------- /MAX3421E.h: -------------------------------------------------------------------------------- 1 | /* MAX3421E support header */ 2 | /* Register names and bit masks for MAX3421 in host mode */ 3 | /* Function prototypes in MAX3421E.c */ 4 | #ifndef _MAX3421E_H_ 5 | #define _MAX3421E_H_ 6 | 7 | /* SPI interface definitions */ 8 | /* SSPSTAT REGISTER */ 9 | 10 | // Master SPI mode only 11 | 12 | #define SMPEND 0x80 // Input data sample at end of data out 13 | #define SMPMID 0x00 // Input data sample at middle of data out 14 | 15 | #define MODE_00 0 // Setting for SPI bus Mode 0,0 16 | //CKE 0x40 // SSPSTAT register 17 | //CKP 0x00 // SSPCON1 register 18 | 19 | #define MODE_01 1 // Setting for SPI bus Mode 0,1 20 | //CKE 0x00 // SSPSTAT register 21 | //CKP 0x00 // SSPCON1 register 22 | 23 | #define MODE_10 2 // Setting for SPI bus Mode 1,0 24 | //CKE 0x40 // SSPSTAT register 25 | //CKP 0x10 // SSPCON1 register 26 | 27 | #define MODE_11 3 // Setting for SPI bus Mode 1,1 28 | //CKE 0x00 // SSPSTAT register 29 | //CKP 0x10 // SSPCON1 register 30 | 31 | /* SSPCON1 REGISTER */ 32 | #define SSPENB 0x20 // Enable serial port and configures SCK, SDO, SDI 33 | 34 | #define SPI_FOSC_4 0 // SPI Master mode, clock = Fosc/4 35 | #define SPI_FOSC_16 1 // SPI Master mode, clock = Fosc/16 36 | #define SPI_FOSC_64 2 // SPI Master mode, clock = Fosc/64 37 | #define SPI_FOSC_TMR2 3 // SPI Master mode, clock = TMR2 output/2 38 | #define SLV_SSON 4 // SPI Slave mode, /SS pin control enabled 39 | #define SLV_SSOFF 5 // SPI Slave mode, /SS pin control disabled 40 | 41 | /* MAX3421E command byte format: rrrrr0wa where 'r' is register number */ 42 | // 43 | // MAX3421E Registers in HOST mode. 44 | // 45 | #define rRCVFIFO 0x08 //1<<3 46 | #define rSNDFIFO 0x10 //2<<3 47 | #define rSUDFIFO 0x20 //4<<3 48 | #define rRCVBC 0x30 //6<<3 49 | #define rSNDBC 0x38 //7<<3 50 | 51 | #define rUSBIRQ 0x68 //13<<3 52 | /* USBIRQ Bits */ 53 | #define bmVBUSIRQ 0x40 //b6 54 | #define bmNOVBUSIRQ 0x20 //b5 55 | #define bmOSCOKIRQ 0x01 //b0 56 | 57 | #define rUSBIEN 0x70 //14<<3 58 | /* USBIEN Bits */ 59 | #define bmVBUSIE 0x40 //b6 60 | #define bmNOVBUSIE 0x20 //b5 61 | #define bmOSCOKIE 0x01 //b0 62 | 63 | #define rUSBCTL 0x78 //15<<3 64 | /* USBCTL Bits */ 65 | #define bmCHIPRES 0x20 //b5 66 | #define bmPWRDOWN 0x10 //b4 67 | 68 | #define rCPUCTL 0x80 //16<<3 69 | /* CPUCTL Bits */ 70 | #define bmPUSLEWID1 0x80 //b7 71 | #define bmPULSEWID0 0x40 //b6 72 | #define bmIE 0x01 //b0 73 | 74 | #define rPINCTL 0x88 //17<<3 75 | /* PINCTL Bits */ 76 | #define bmFDUPSPI 0x10 //b4 77 | #define bmINTLEVEL 0x08 //b3 78 | #define bmPOSINT 0x04 //b2 79 | #define bmGPXB 0x02 //b1 80 | #define bmGPXA 0x01 //b0 81 | // GPX pin selections 82 | #define GPX_OPERATE 0x00 83 | #define GPX_VBDET 0x01 84 | #define GPX_BUSACT 0x02 85 | #define GPX_SOF 0x03 86 | 87 | #define rREVISION 0x90 //18<<3 88 | 89 | #define rIOPINS1 0xa0 //20<<3 90 | 91 | /* IOPINS1 Bits */ 92 | #define bmGPOUT0 0x01 93 | #define bmGPOUT1 0x02 94 | #define bmGPOUT2 0x04 95 | #define bmGPOUT3 0x08 96 | #define bmGPIN0 0x10 97 | #define bmGPIN1 0x20 98 | #define bmGPIN2 0x40 99 | #define bmGPIN3 0x80 100 | 101 | #define rIOPINS2 0xa8 //21<<3 102 | /* IOPINS2 Bits */ 103 | #define bmGPOUT4 0x01 104 | #define bmGPOUT5 0x02 105 | #define bmGPOUT6 0x04 106 | #define bmGPOUT7 0x08 107 | #define bmGPIN4 0x10 108 | #define bmGPIN5 0x20 109 | #define bmGPIN6 0x40 110 | #define bmGPIN7 0x80 111 | 112 | #define rGPINIRQ 0xb0 //22<<3 113 | /* GPINIRQ Bits */ 114 | #define bmGPINIRQ0 0x01 115 | #define bmGPINIRQ1 0x02 116 | #define bmGPINIRQ2 0x04 117 | #define bmGPINIRQ3 0x08 118 | #define bmGPINIRQ4 0x10 119 | #define bmGPINIRQ5 0x20 120 | #define bmGPINIRQ6 0x40 121 | #define bmGPINIRQ7 0x80 122 | 123 | #define rGPINIEN 0xb8 //23<<3 124 | /* GPINIEN Bits */ 125 | #define bmGPINIEN0 0x01 126 | #define bmGPINIEN1 0x02 127 | #define bmGPINIEN2 0x04 128 | #define bmGPINIEN3 0x08 129 | #define bmGPINIEN4 0x10 130 | #define bmGPINIEN5 0x20 131 | #define bmGPINIEN6 0x40 132 | #define bmGPINIEN7 0x80 133 | 134 | #define rGPINPOL 0xc0 //24<<3 135 | /* GPINPOL Bits */ 136 | #define bmGPINPOL0 0x01 137 | #define bmGPINPOL1 0x02 138 | #define bmGPINPOL2 0x04 139 | #define bmGPINPOL3 0x08 140 | #define bmGPINPOL4 0x10 141 | #define bmGPINPOL5 0x20 142 | #define bmGPINPOL6 0x40 143 | #define bmGPINPOL7 0x80 144 | 145 | #define rHIRQ 0xc8 //25<<3 146 | /* HIRQ Bits */ 147 | #define bmBUSEVENTIRQ 0x01 // indicates BUS Reset Done or BUS Resume 148 | #define bmRWUIRQ 0x02 149 | #define bmRCVDAVIRQ 0x04 150 | #define bmSNDBAVIRQ 0x08 151 | #define bmSUSDNIRQ 0x10 152 | #define bmCONDETIRQ 0x20 153 | #define bmFRAMEIRQ 0x40 154 | #define bmHXFRDNIRQ 0x80 155 | 156 | #define rHIEN 0xd0 //26<<3 157 | /* HIEN Bits */ 158 | #define bmBUSEVENTIE 0x01 159 | #define bmRWUIE 0x02 160 | #define bmRCVDAVIE 0x04 161 | #define bmSNDBAVIE 0x08 162 | #define bmSUSDNIE 0x10 163 | #define bmCONDETIE 0x20 164 | #define bmFRAMEIE 0x40 165 | #define bmHXFRDNIE 0x80 166 | 167 | #define rMODE 0xd8 //27<<3 168 | /* MODE Bits */ 169 | #define bmHOST 0x01 170 | #define bmLOWSPEED 0x02 171 | #define bmHUBPRE 0x04 172 | #define bmSOFKAENAB 0x08 173 | #define bmSEPIRQ 0x10 174 | #define bmDELAYISO 0x20 175 | #define bmDMPULLDN 0x40 176 | #define bmDPPULLDN 0x80 177 | 178 | #define rPERADDR 0xe0 //28<<3 179 | 180 | #define rHCTL 0xe8 //29<<3 181 | /* HCTL Bits */ 182 | #define bmBUSRST 0x01 183 | #define bmFRMRST 0x02 184 | #define bmSAMPLEBUS 0x04 185 | #define bmSIGRSM 0x08 186 | #define bmRCVTOG0 0x10 187 | #define bmRCVTOG1 0x20 188 | #define bmSNDTOG0 0x40 189 | #define bmSNDTOG1 0x80 190 | 191 | 192 | 193 | #define rHXFR 0xf0 //30<<3 194 | /* Host transfer token values for writing the HXFR register (R30) */ 195 | /* OR this bit field with the endpoint number in bits 3:0 */ 196 | #define tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1 197 | #define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0 198 | #define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0 199 | #define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0 200 | #define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0 201 | #define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0 202 | #define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0 203 | 204 | #define rHRSL 0xf8 //31<<3 205 | /* HRSL Bits */ 206 | #define bmRCVTOGRD 0x10 207 | #define bmSNDTOGRD 0x20 208 | #define bmKSTATUS 0x40 209 | #define bmJSTATUS 0x80 210 | #define bmSE0 0x00 //SE0 - disconnect state 211 | #define bmSE1 0xc0 //SE1 - illegal state 212 | /* Host error result codes, the 4 LSB's in the HRSL register */ 213 | #define hrSUCCESS 0x00 214 | #define hrBUSY 0x01 215 | #define hrBADREQ 0x02 216 | #define hrUNDEF 0x03 217 | #define hrNAK 0x04 218 | #define hrSTALL 0x05 219 | #define hrTOGERR 0x06 220 | #define hrWRONGPID 0x07 221 | #define hrBADBC 0x08 222 | #define hrPIDERR 0x09 223 | #define hrPKTERR 0x0A 224 | #define hrCRCERR 0x0B 225 | #define hrKERR 0x0C 226 | #define hrJERR 0x0D 227 | #define hrTIMEOUT 0x0E 228 | #define hrBABBLE 0x0F 229 | 230 | #define MODE_FS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB) 231 | #define MODE_LS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB) 232 | 233 | 234 | /* MAX3421E.c function prototypes */ 235 | void SPI_init( BYTE sync_mode, BYTE bus_mode, BYTE smp_phase ); 236 | BYTE SPI_wr( BYTE data ); 237 | void MAXreg_wr( BYTE reg, BYTE val ); 238 | char* MAXbytes_wr( BYTE reg, BYTE nbytes, BYTE * data ); 239 | BYTE MAXreg_rd( BYTE reg ); 240 | char* MAXbytes_rd ( BYTE reg, BYTE nbytes, BYTE *data ); 241 | void MAX3421E_reset( void ); 242 | BOOL Vbus_power ( BOOL action ); 243 | void MAX3421E_init( void ); 244 | void MAX_busprobe( void ); 245 | void MAX3421E_Task( void ); 246 | void MaxIntHandler( void ); 247 | void MaxGpxHandler( void ); 248 | 249 | #endif //_MAX3421E_H_ 250 | 251 | -------------------------------------------------------------------------------- /usb_ch9.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | USB Chapter 9 Protocol (Header File) 4 | 5 | This file defines data structures, constants, and macros that are used to 6 | to support the USB Device Framework protocol described in Chapter 9 of the 7 | USB 2.0 specification. 8 | 9 | In addition to that, class-specific descriptors are typedef'd here as well to keep descriptors together. 10 | They are typedefs anyway and won't take any real code space. 11 | */ 12 | 13 | #ifndef _USB_CH9_H_ 14 | #define _USB_CH9_H_ 15 | 16 | /* Misc.USB constants */ 17 | #define DEV_DESCR_LEN 18 //device descriptor length 18 | #define CONF_DESCR_LEN 9 //configuration descriptor length 19 | #define INTR_DESCR_LEN 9 //interface descriptor length 20 | #define EP_DESCR_LEN 7 //endpoint descriptor length 21 | /* Device descriptor structure */ 22 | typedef struct { 23 | BYTE bLength; // Length of this descriptor. 24 | BYTE bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE). 25 | WORD bcdUSB; // USB Spec Release Number (BCD). 26 | BYTE bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. 27 | BYTE bDeviceSubClass; // Subclass code (assigned by the USB-IF). 28 | BYTE bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. 29 | BYTE bMaxPacketSize0; // Maximum packet size for endpoint 0. 30 | WORD idVendor; // Vendor ID (assigned by the USB-IF). 31 | WORD idProduct; // Product ID (assigned by the manufacturer). 32 | WORD bcdDevice; // Device release number (BCD). 33 | BYTE iManufacturer; // Index of String Descriptor describing the manufacturer. 34 | BYTE iProduct; // Index of String Descriptor describing the product. 35 | BYTE iSerialNumber; // Index of String Descriptor with the device's serial number. 36 | BYTE bNumConfigurations; // Number of possible configurations. 37 | } USB_DEVICE_DESCRIPTOR; 38 | /* Configuration Descriptor Structure */ 39 | typedef struct { 40 | BYTE bLength; // Length of this descriptor. 41 | BYTE bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). 42 | WORD wTotalLength; // Total length of all descriptors for this configuration. 43 | BYTE bNumInterfaces; // Number of interfaces in this configuration. 44 | BYTE bConfigurationValue; // Value of this configuration (1 based). 45 | BYTE iConfiguration; // Index of String Descriptor describing the configuration. 46 | BYTE bmAttributes; // Configuration characteristics. 47 | BYTE bMaxPower; // Maximum power consumed by this configuration. 48 | } USB_CONFIGURATION_DESCRIPTOR; 49 | /* Conf.descriptor attribute bits */ 50 | #define USB_CFG_DSC_REQUIRED 0x80 // Required attribute 51 | //#define USB_CFG_DSC_SELF_PWR (0x40|USB_CFG_DSC_REQUIRED) // Device is self powered. 52 | //#define USB_CFG_DSC_REM_WAKE (0x20|USB_CFG_DSC_REQUIRED) // Device can request remote wakup 53 | #define USB_CFG_DSC_SELF_PWR (0x40) // Device is self powered. 54 | #define USB_CFG_DSC_REM_WAKE (0x20) // Device can request remote wakup 55 | /* USB Interface Descriptor Structure */ 56 | typedef struct { 57 | BYTE bLength; // Length of this descriptor. 58 | BYTE bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). 59 | BYTE bInterfaceNumber; // Number of this interface (0 based). 60 | BYTE bAlternateSetting; // Value of this alternate interface setting. 61 | BYTE bNumEndpoints; // Number of endpoints in this interface. 62 | BYTE bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. 63 | BYTE bInterfaceSubClass; // Subclass code (assigned by the USB-IF). 64 | BYTE bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. 65 | BYTE iInterface; // Index of String Descriptor describing the interface. 66 | } USB_INTERFACE_DESCRIPTOR; 67 | /* USB Endpoint Descriptor Structure */ 68 | typedef struct { 69 | BYTE bLength; // Length of this descriptor. 70 | BYTE bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). 71 | BYTE bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN). 72 | BYTE bmAttributes; // Endpoint transfer type. 73 | WORD wMaxPacketSize; // Maximum packet size. 74 | BYTE bInterval; // Polling interval in frames. 75 | } USB_ENDPOINT_DESCRIPTOR; 76 | /* Endpoint Direction */ 77 | #define EP_DIR_IN 0x80 // Data flows from device to host 78 | #define EP_DIR_OUT 0x00 // Data flows from host to device 79 | /* USB Endpoint Attributes */ 80 | // Section: Transfer Types 81 | #define EP_ATTR_CONTROL (0<<0) // Endoint used for control transfers 82 | #define EP_ATTR_ISOCH (1<<0) // Endpoint used for isochronous transfers 83 | #define EP_ATTR_BULK (2<<0) // Endpoint used for bulk transfers 84 | #define EP_ATTR_INTR (3<<0) // Endpoint used for interrupt transfers 85 | // Section: Synchronization Types (for isochronous enpoints) 86 | #define EP_ATTR_NO_SYNC (0<<2) // No Synchronization 87 | #define EP_ATTR_ASYNC (1<<2) // Asynchronous 88 | #define EP_ATTR_ADAPT (2<<2) // Adaptive synchronization 89 | #define EP_ATTR_SYNC (3<<2) // Synchronous 90 | // Section: Usage Types (for isochronous endpoints) 91 | #define EP_ATTR_DATA (0<<4) // Data Endpoint 92 | #define EP_ATTR_FEEDBACK (1<<4) // Feedback endpoint 93 | #define EP_ATTR_IMP_FB (2<<4) // Implicit Feedback data EP 94 | // Section: Max Packet Sizes 95 | #define EP_MAX_PKT_INTR_LS 8 // Max low-speed interrupt packet 96 | #define EP_MAX_PKT_INTR_FS 64 // Max full-speed interrupt packet 97 | #define EP_MAX_PKT_ISOCH_FS 1023 // Max full-speed isochronous packet 98 | #define EP_MAX_PKT_BULK_FS 64 // Max full-speed bulk packet 99 | #define EP_LG_PKT_BULK_FS 32 // Large full-speed bulk packet 100 | #define EP_MED_PKT_BULK_FS 16 // Medium full-speed bulk packet 101 | #define EP_SM_PKT_BULK_FS 8 // Small full-speed bulk packet 102 | /* USB OTG Descriptor Structure */ 103 | typedef struct { 104 | BYTE bLength; // Length of this descriptor. 105 | BYTE bDescriptorType; // OTG descriptor type (USB_DESCRIPTOR_OTG). 106 | BYTE bmAttributes; // OTG attributes. 107 | } USB_OTG_DESCRIPTOR; 108 | /* USB String Descriptor Structure */ 109 | typedef struct { 110 | BYTE bLength; //size of this descriptor 111 | BYTE bDescriptorType; //type, USB_DSC_STRING 112 | BYTE bString[64]; //buffer for string 113 | } USB_STRING_DESCRIPTOR; 114 | /* Section: USB Device Qualifier Descriptor Structure */ 115 | typedef struct { 116 | BYTE bLength; // Size of this descriptor 117 | BYTE bDescriptorType; // Type, always USB_DESCRIPTOR_DEVICE_QUALIFIER 118 | WORD bcdUSB; // USB spec version, in BCD 119 | BYTE bDeviceClass; // Device class code 120 | BYTE bDeviceSubClass; // Device sub-class code 121 | BYTE bDeviceProtocol; // Device protocol 122 | BYTE bMaxPacketSize0; // EP0, max packet size 123 | BYTE bNumConfigurations; // Number of "other-speed" configurations 124 | BYTE bReserved; // Always zero (0) 125 | } USB_DEVICE_QUALIFIER_DESCRIPTOR; 126 | /* Section: USB Specification Constants */ 127 | #define PID_OUT 0x1 // PID for an OUT token 128 | #define PID_ACK 0x2 // PID for an ACK handshake 129 | #define PID_DATA0 0x3 // PID for DATA0 data 130 | #define PID_PING 0x4 // Special PID PING 131 | #define PID_SOF 0x5 // PID for a SOF token 132 | #define PID_NYET 0x6 // PID for a NYET handshake 133 | #define PID_DATA2 0x7 // PID for DATA2 data 134 | #define PID_SPLIT 0x8 // Special PID SPLIT 135 | #define PID_IN 0x9 // PID for a IN token 136 | #define PID_NAK 0xA // PID for a NAK handshake 137 | #define PID_DATA1 0xB // PID for DATA1 data 138 | #define PID_PRE 0xC // Special PID PRE (Same as PID_ERR) 139 | #define PID_ERR 0xC // Special PID ERR (Same as PID_PRE) 140 | #define PID_SETUP 0xD // PID for a SETUP token 141 | #define PID_STALL 0xE // PID for a STALL handshake 142 | #define PID_MDATA 0xF // PID for MDATA data 143 | 144 | #define PID_MASK_DATA 0x03 // Data PID mask 145 | #define PID_MASK_DATA_SHIFTED (PID_MASK_DATA << 2) // Data PID shift to proper position 146 | 147 | /* USB Token Types */ 148 | /* defined in MAX3421E.h */ 149 | 150 | /* Section: OTG Descriptor Constants */ 151 | #define OTG_HNP_SUPPORT 0x02 // OTG Descriptor bmAttributes - HNP support flag 152 | #define OTG_SRP_SUPPORT 0x01 // OTG Descriptor bmAttributes - SRP support flag 153 | /* Section: USB Class Code Definitions */ 154 | #define USB_HUB_CLASSCODE 0x09 // Class code for a hub. 155 | 156 | /* HID class-specific defines */ 157 | 158 | /* USB HID Descriptor header per HID 1.1 spec */ 159 | /* section 6.2.1 */ 160 | /* the header is variable length. Only first class descriptor fields are defined */ 161 | typedef struct { 162 | BYTE bLength; 163 | BYTE bDescriptorType; 164 | WORD bcdHID; 165 | BYTE bCountryCode; 166 | BYTE bNumDescriptors; 167 | BYTE bDescrType; 168 | WORD wDescriptorLength; 169 | } USB_HID_DESCRIPTOR; 170 | 171 | /* combined descriptor for easy parsing */ 172 | typedef struct { 173 | union { 174 | BYTE buf[ 80 ]; 175 | USB_DEVICE_DESCRIPTOR device; 176 | USB_CONFIGURATION_DESCRIPTOR config; 177 | USB_INTERFACE_DESCRIPTOR interface; 178 | USB_ENDPOINT_DESCRIPTOR endpoint; 179 | USB_STRING_DESCRIPTOR string; 180 | /* class descriptors */ 181 | USB_HID_DESCRIPTOR HID; 182 | }descr; 183 | } USB_DESCR; 184 | #endif // _USB_CH9_H_ 185 | 186 | -------------------------------------------------------------------------------- /HID.c: -------------------------------------------------------------------------------- 1 | /* HID class support functions */ 2 | 3 | #include "project_config.h" 4 | 5 | extern char bigbuf[]; //256 bytes 6 | extern DEV_RECORD devtable[]; 7 | 8 | HID_DEVICE hid_device = {{ 0 }}; 9 | EP_RECORD hid_ep[ 2 ] = {{ 0 }}; //HID class endpoints, 1 control, 1 interrupt-IN 10 | //the third endpoint is not implemented 11 | 12 | /* HID Mouse probe. Called from USB state machine. */ 13 | /* assumes configuration length is less than 256 bytes */ 14 | /* looks for Class:03, Subclass: 01, Protocol: 02 in interface descriptor */ 15 | /* sets mouse in boot protocol */ 16 | /* assumes single configuration and interface configuration 0 */ 17 | BOOL HIDMProbe( BYTE addr, DWORD flags ) 18 | { 19 | BYTE tmpbyte; 20 | BYTE rcode; 21 | BYTE confvalue; 22 | WORD total_length; 23 | USB_DESCR* data_ptr = ( USB_DESCR * )&bigbuf; 24 | char* byte_ptr = bigbuf; 25 | rcode = XferGetConfDescr( addr, 0, CONF_DESCR_LEN, 0, bigbuf ); //get configuration descriptor 26 | if( rcode ) { //error handling 27 | return( FALSE ); 28 | } 29 | if( data_ptr->descr.config.wTotalLength > 256 ) { 30 | total_length = 256; 31 | } 32 | else { 33 | total_length = data_ptr->descr.config.wTotalLength; 34 | } 35 | rcode = XferGetConfDescr( addr, 0, total_length, 0, bigbuf ); //get the whole configuration 36 | if( rcode ) { //error handling 37 | return( FALSE ); 38 | } 39 | confvalue = data_ptr->descr.config.bConfigurationValue; 40 | while( byte_ptr < bigbuf + total_length ) { 41 | if( data_ptr->descr.config.bDescriptorType != USB_DESCRIPTOR_INTERFACE ) { 42 | byte_ptr = byte_ptr + data_ptr->descr.config.bLength; 43 | data_ptr = ( USB_DESCR* )byte_ptr; 44 | }// if( data_ptr->descr.config.bDescriptorType != USB_DESCRIPTOR_INTERFACE 45 | else { //interface descriptor 46 | if( data_ptr->descr.interface.bInterfaceClass == HID_INTF && 47 | data_ptr->descr.interface.bInterfaceSubClass == BOOT_INTF_SUBCLASS && 48 | data_ptr->descr.interface.bInterfaceProtocol == HID_PROTOCOL_MOUSE ) { 49 | devtable[ addr ].devclass = HID_M; //device class 50 | tmpbyte = devtable[ addr ].epinfo->MaxPktSize; 51 | HID_init(); //initialize data structures 52 | devtable[ addr ].epinfo = hid_ep; //switch endpoint information structure 53 | devtable[ addr ].epinfo[ 0 ].MaxPktSize = tmpbyte; 54 | hid_device.interface = data_ptr->descr.interface.bInterfaceNumber; 55 | hid_device.addr = addr; 56 | byte_ptr = byte_ptr + data_ptr->descr.config.bLength; 57 | data_ptr = ( USB_DESCR* )byte_ptr; 58 | while( byte_ptr < bigbuf + total_length ) { 59 | if( data_ptr->descr.config.bDescriptorType != USB_DESCRIPTOR_ENDPOINT ) { //skip to endpoint descriptor 60 | byte_ptr = byte_ptr + data_ptr->descr.config.bLength; 61 | data_ptr = ( USB_DESCR* )byte_ptr; 62 | } 63 | else { 64 | /* fill endpoint information structure */ 65 | devtable[ addr ].epinfo[ 1 ].epAddr = data_ptr->descr.endpoint.bEndpointAddress; 66 | devtable[ addr ].epinfo[ 1 ].Attr = data_ptr->descr.endpoint.bmAttributes; 67 | devtable[ addr ].epinfo[ 1 ].MaxPktSize = data_ptr->descr.endpoint.wMaxPacketSize; 68 | devtable[ addr ].epinfo[ 1 ].Interval = data_ptr->descr.endpoint.bInterval; 69 | // devtable[ addr ].epinfo[ 1 ].rcvToggle = bmRCVTOG0; 70 | /* configure device */ 71 | rcode = XferSetConf( addr, 0, confvalue ); //set configuration 72 | if( rcode ) { //error handling 73 | return( FALSE ); 74 | } 75 | rcode = XferSetProto( addr, 0, hid_device.interface, BOOT_PROTOCOL ); 76 | if( rcode ) { //error handling 77 | return( FALSE ); 78 | } 79 | else { 80 | return( TRUE ); 81 | } 82 | } 83 | }//while( byte_ptr.... 84 | }//if (Class matches 85 | else { //if class don't match; die on first interface. Not really correct 86 | return( FALSE ); 87 | } 88 | }//else if( data_ptr-> 89 | }// while( byte_ptr < &buf + total_length 90 | return( FALSE ); 91 | } 92 | /* HID Keyboard probe. Called from USB state machine. */ 93 | /* assumes configuration length is less than 256 bytes */ 94 | /* looks for Class:03, Subclass: 01, Protocol: 01 in interface descriptor */ 95 | /* sets keyboard in boot protocol */ 96 | /* assumes single configuration, single endpoint, and interface configuration 0 */ 97 | BOOL HIDKProbe( BYTE addr, DWORD flags ) 98 | { 99 | BYTE tmpbyte; 100 | BYTE rcode; 101 | BYTE confvalue; 102 | WORD total_length; 103 | USB_DESCR* data_ptr = ( USB_DESCR * )&bigbuf; 104 | char* byte_ptr = bigbuf; 105 | rcode = XferGetConfDescr( addr, 0, CONF_DESCR_LEN, 0, bigbuf ); //get configuration descriptor 106 | if( rcode ) { //error handling 107 | return( FALSE ); 108 | } 109 | if( data_ptr->descr.config.wTotalLength > 256 ) { 110 | total_length = 256; 111 | } 112 | else { 113 | total_length = data_ptr->descr.config.wTotalLength; 114 | } 115 | rcode = XferGetConfDescr( addr, 0, total_length, 0, bigbuf ); //get the whole configuration 116 | if( rcode ) { //error handling 117 | return( FALSE ); 118 | } 119 | confvalue = data_ptr->descr.config.bConfigurationValue; //save configuration value to use later 120 | while( byte_ptr < bigbuf + total_length ) { //parse configuration 121 | if( data_ptr->descr.config.bDescriptorType != USB_DESCRIPTOR_INTERFACE ) { //skip to the next descriptor 122 | byte_ptr = byte_ptr + data_ptr->descr.config.bLength; 123 | data_ptr = ( USB_DESCR* )byte_ptr; 124 | }// if( data_ptr->descr.config.bDescriptorType != USB_DESCRIPTOR_INTERFACE 125 | else { //interface descriptor 126 | if( data_ptr->descr.interface.bInterfaceClass == HID_INTF && 127 | data_ptr->descr.interface.bInterfaceSubClass == BOOT_INTF_SUBCLASS && 128 | data_ptr->descr.interface.bInterfaceProtocol == HID_PROTOCOL_KEYBOARD ) { 129 | devtable[ addr ].devclass = HID_K; //fill device class 130 | tmpbyte = devtable[ addr ].epinfo->MaxPktSize; //save max.packet size 131 | HID_init(); //initialize data structures 132 | devtable[ addr ].epinfo = hid_ep; //switch endpoint information structure 133 | devtable[ addr ].epinfo[ 0 ].MaxPktSize = tmpbyte; //fill in max.packet size 134 | hid_device.interface = data_ptr->descr.interface.bInterfaceNumber; //fill in interface number to be used in HID requests 135 | hid_device.addr = addr; //fill in address 136 | byte_ptr = byte_ptr + data_ptr->descr.config.bLength; //skip to the next descriptor 137 | data_ptr = ( USB_DESCR* )byte_ptr; 138 | while( byte_ptr < bigbuf + total_length ) { 139 | if( data_ptr->descr.config.bDescriptorType != USB_DESCRIPTOR_ENDPOINT ) { //skip to endpoint descriptor 140 | byte_ptr = byte_ptr + data_ptr->descr.config.bLength; 141 | data_ptr = ( USB_DESCR* )byte_ptr; 142 | } 143 | else { 144 | /* fill endpoint information structure */ 145 | devtable[ addr ].epinfo[ 1 ].epAddr = data_ptr->descr.endpoint.bEndpointAddress; 146 | devtable[ addr ].epinfo[ 1 ].Attr = data_ptr->descr.endpoint.bmAttributes; 147 | devtable[ addr ].epinfo[ 1 ].MaxPktSize = data_ptr->descr.endpoint.wMaxPacketSize; 148 | devtable[ addr ].epinfo[ 1 ].Interval = data_ptr->descr.endpoint.bInterval; 149 | /* configure device */ 150 | rcode = XferSetConf( addr, 0, confvalue ); //set configuration 151 | if( rcode ) { //error handling 152 | return( FALSE ); 153 | } 154 | rcode = XferSetProto( addr, 0, hid_device.interface, BOOT_PROTOCOL ); 155 | if( rcode ) { //error handling 156 | return( FALSE ); 157 | } 158 | else { 159 | return( TRUE ); 160 | } 161 | } 162 | }//while( byte_ptr.... 163 | }//if (Class matches 164 | else { //if class don't match; stop processing after first interface. Not really correct 165 | return( FALSE ); 166 | } 167 | }//else if( data_ptr-> 168 | }// while( byte_ptr < &buf + total_length 169 | return( FALSE ); 170 | } 171 | /* HID data structures initialization */ 172 | void HID_init( void ) 173 | { 174 | hid_ep[ 1 ].sndToggle = bmSNDTOG0; 175 | hid_ep[ 1 ].rcvToggle = bmRCVTOG0; 176 | } 177 | /* poll boot mouse */ 178 | BYTE mousePoll( BOOT_MOUSE_REPORT* buf ) 179 | { 180 | BYTE rcode; 181 | MAXreg_wr( rPERADDR, hid_device.addr ); //set peripheral address 182 | rcode = XferInTransfer( hid_device.addr, 1, 8, ( char* )buf, devtable[ hid_device.addr ].epinfo[ 1 ].MaxPktSize ); 183 | return( rcode ); 184 | } 185 | /* poll boot keyboard */ 186 | BYTE kbdPoll( BOOT_KBD_REPORT* buf ) 187 | { 188 | BYTE rcode; 189 | MAXreg_wr( rPERADDR, hid_device.addr ); //set peripheral address 190 | rcode = XferInTransfer( hid_device.addr, 1, 8, ( char* )buf, devtable[ hid_device.addr ].epinfo[ 1 ].MaxPktSize ); 191 | return( rcode ); 192 | } 193 | BOOL HIDMEventHandler( BYTE address, BYTE event, void *data, DWORD size ) 194 | { 195 | return( FALSE ); 196 | } 197 | BOOL HIDKEventHandler( BYTE address, BYTE event, void *data, DWORD size ) 198 | { 199 | return( FALSE ); 200 | } 201 | -------------------------------------------------------------------------------- /MAX3421E.c: -------------------------------------------------------------------------------- 1 | /* MAX3421E low-level functions */ 2 | /* reading, writing registers, reset, host transfer, etc. */ 3 | /* GPIN, GPOUT are as per tutorial, reassign if necessary */ 4 | /* USB power on is GPOUT7, USB power overload is GPIN7 */ 5 | 6 | #define _MAX3421E_C_ 7 | 8 | #include "project_config.h" 9 | 10 | /* variables and data structures */ 11 | 12 | 13 | 14 | /* External variables */ 15 | 16 | extern DWORD uptime; 17 | extern BYTE usb_task_state; 18 | 19 | 20 | /* Functions */ 21 | 22 | /* SPI initialization */ 23 | /* this routine was borrowed from Microchip peripheral library. It's been rumored that they're going to stop including 24 | peripherals with new releases of C18 so I make a copy just in case. 25 | 26 | sync_mode: 27 | SPI_FOSC_4 SPI Master mode, clock = FOSC/4 28 | SPI_FOSC_16 SPI Master mode, clock = FOSC/16 29 | SPI_FOSC_64 SPI Master mode, clock = FOSC/64 30 | SPI_FOSC_TMR2 SPI Master mode, clock = TMR2 output/2 31 | SLV_SSON SPI Slave mode, /SS pin control enabled 32 | SLV_SSOFF SPI Slave mode, /SS pin control disabled 33 | bus_mode: 34 | MODE_00 SPI bus Mode 0,0 35 | MODE_01 SPI bus Mode 0,1 36 | MODE_10 SPI bus Mode 1,0 37 | MODE_11 SPI bus Mode 1,1 38 | smp_phase: 39 | SMPEND Input data sample at end of data out 40 | SMPMID Input data sample at middle of data out 41 | */ 42 | void SPI_init( BYTE sync_mode, BYTE bus_mode, BYTE smp_phase ) 43 | { 44 | SSPSTAT &= 0x3f; //power-on state 45 | SSPCON1 = 0x00; //power-on state, SSP disabled 46 | SSPCON1 |= sync_mode; 47 | SSPSTAT |= smp_phase; 48 | 49 | switch( bus_mode ) { 50 | case 0: // SPI1 bus mode 0,0 51 | SSPSTATbits.CKE = 1; // data transmitted on rising edge 52 | break; 53 | case 2: // SPI1 bus mode 1,0 54 | SSPSTATbits.CKE = 1; // data transmitted on falling edge 55 | SSPCON1bits.CKP = 1; // clock idle state high 56 | break; 57 | case 3: // SPI1 bus mode 1,1 58 | SSPCON1bits.CKP = 1; // clock idle state high 59 | break; 60 | default: // default SPI1 bus mode 0,1 61 | break; 62 | } 63 | 64 | switch( sync_mode ) { 65 | case 4: // slave mode w /SS1 enable 66 | TRISAbits.TRISA5 = 1; // define /SS1 pin as input 67 | case 5: // slave mode w/o /SS1 enable 68 | TRISCbits.TRISC3 = 1; // define clock pin as input 69 | SSPSTATbits.SMP = 0; // must be cleared in slave SPI mode 70 | break; 71 | default: // master mode, define clock pin as output 72 | TRISCbits.TRISC3 = 0; // define clock pin as output 73 | break; 74 | } 75 | 76 | TRISC &= 0xDF; // define SDO as output (master or slave) 77 | TRISC |= 0x10; // define SDI as input (master or slave) 78 | // IPR1bits.SSPIP = 0; //low-priority interrupt 79 | // PIE1bits.SSPIE = 1; //interrupt enable 80 | SSPCON1 |= SSPENB; // enable synchronous serial port 81 | } 82 | 83 | /* writes to SPI. BF is checked inside the procedure */ 84 | /* returns SSPBUF */ 85 | BYTE SPI_wr( BYTE data ) 86 | { 87 | SSPBUF = data; // write byte to SSP2BUF register 88 | while( !SSPSTATbits.BF ); // wait until bus cycle completes 89 | return ( SSPBUF ); // 90 | } 91 | /* Single host register write */ 92 | void MAXreg_wr(BYTE reg, BYTE val) 93 | { 94 | Select_MAX3421E; 95 | SPI_wr ( reg + 2 ); //set WR bit and send register number 96 | SPI_wr ( val ); 97 | Deselect_MAX3421E; 98 | } 99 | /* multiple-byte write */ 100 | /* returns a pointer to a memory position after last written */ 101 | char* MAXbytes_wr( BYTE reg, BYTE nbytes, char* data ) 102 | { 103 | Select_MAX3421E; //assert SS 104 | SPI_wr ( reg + 2 ); //set W/R bit and select register 105 | while( nbytes ) { 106 | SPI_wr( *data ); // send the next data byte 107 | data++; // advance the pointer 108 | nbytes--; 109 | } 110 | Deselect_MAX3421E; //deassert SS 111 | return( data ); 112 | } 113 | /* Single host register read */ 114 | BYTE MAXreg_rd( BYTE reg ) 115 | { 116 | BYTE tmp; 117 | Select_MAX3421E; 118 | SPI_wr ( reg ); //send register number 119 | tmp = SPI_wr ( 0x00 ); //send empty byte, read register contents 120 | Deselect_MAX3421E; 121 | return (tmp); 122 | } 123 | /* multiple-bytes register read */ 124 | /* returns a pointer to a memory position after last read */ 125 | char* MAXbytes_rd ( BYTE reg, BYTE nbytes, char* data ) 126 | { 127 | Select_MAX3421E; //assert SS 128 | SPI_wr ( reg ); //send register number 129 | while( nbytes ) { 130 | *data = SPI_wr ( 0x00 ); //send empty byte, read register contents 131 | data++; 132 | nbytes--; 133 | } 134 | Deselect_MAX3421E; //deassert SS 135 | return( data ); 136 | } 137 | /* reset MAX3421E using chip reset bit. SPI configuration is not affected */ 138 | void MAX3421E_reset( void ) 139 | { 140 | BYTE tmp = 0; 141 | MAXreg_wr( rUSBCTL,bmCHIPRES ); //Chip reset. This stops the oscillator 142 | MAXreg_wr( rUSBCTL,0x00 ); //Remove the reset 143 | while(!(MAXreg_rd( rUSBIRQ ) & bmOSCOKIRQ )) { //wait until the PLL stabilizes 144 | tmp++; //timeout after 256 attempts 145 | if( tmp == 0 ) break; 146 | } 147 | } 148 | /* turn USB power on/off */ 149 | /* ON pin of VBUS switch (MAX4793 or similar) is connected to GPOUT7 */ 150 | /* OVERLOAD pin of Vbus switch is connected to GPIN7 */ 151 | /* OVERLOAD state low. NO OVERLOAD or VBUS OFF state high. */ 152 | BOOL Vbus_power ( BOOL action ) 153 | { 154 | BYTE tmp = MAXreg_rd( rIOPINS2 ); //copy of IOPINS2 155 | if( action ) { //turn on by setting GPOUT7 156 | tmp |= bmGPOUT7; 157 | } 158 | else { //turn off by clearing GPOUT7 159 | tmp &= ~bmGPOUT7; 160 | } 161 | MAXreg_wr( rIOPINS2,tmp ); //send GPOUT7 162 | if( action ) Delay10KTCYx( 60 ); //wait 60ms for Vbus to stabilize 163 | if (!(MAXreg_rd( rIOPINS2 )&bmGPIN7)) return( FALSE ); // check if overload is present 164 | return( TRUE ); // power on/off successful 165 | } 166 | 167 | /* probe bus to determine device presense and speed */ 168 | void MAX_busprobe( void ) 169 | { 170 | BYTE bus_sample; 171 | 172 | // MAXreg_wr(rHCTL,bmSAMPLEBUS); 173 | bus_sample = MAXreg_rd( rHRSL ); //Get J,K status 174 | bus_sample &= ( bmJSTATUS|bmKSTATUS ); //zero the rest of the byte 175 | 176 | switch( bus_sample ) { //start full-speed or low-speed host 177 | case( bmJSTATUS ): 178 | /*kludgy*/ 179 | if( usb_task_state != USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE ) { //bus reset causes connection detect interrupt 180 | if( !(MAXreg_rd( rMODE ) & bmLOWSPEED )) { 181 | MAXreg_wr( rMODE, MODE_FS_HOST ); //start full-speed host 182 | } 183 | else { 184 | MAXreg_wr( rMODE, MODE_LS_HOST); //start low-speed host 185 | } 186 | usb_task_state = ( USB_STATE_ATTACHED ); //signal usb state machine to start attachment sequence 187 | } 188 | break; 189 | case( bmKSTATUS ): 190 | if( usb_task_state != USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE ) { //bus reset causes connection detect interrupt 191 | if( !(MAXreg_rd( rMODE ) & bmLOWSPEED )) { 192 | MAXreg_wr( rMODE, MODE_LS_HOST ); //start low-speed host 193 | } 194 | else { 195 | MAXreg_wr( rMODE, MODE_FS_HOST ); //start full-speed host 196 | } 197 | usb_task_state = ( USB_STATE_ATTACHED ); //signal usb state machine to start attachment sequence 198 | } 199 | break; 200 | case( bmSE1 ): //illegal state 201 | usb_task_state = ( USB_DETACHED_SUBSTATE_ILLEGAL ); 202 | break; 203 | case( bmSE0 ): //disconnected state 204 | if( !(( usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED )) //if we came here from other than detached state 205 | usb_task_state = ( USB_DETACHED_SUBSTATE_INITIALIZE ); //clear device data structures 206 | else { 207 | MAXreg_wr( rMODE, MODE_FS_HOST ); //start full-speed host 208 | usb_task_state = ( USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE ); 209 | } 210 | break; 211 | }//end switch( bus_sample ) 212 | } 213 | /* MAX3421E initialization after power-on */ 214 | void MAX3421E_init( void ) 215 | { 216 | BYTE tmp; 217 | /* Configure full-duplex SPI, interrupt pulse */ 218 | MAXreg_wr( rPINCTL,(bmFDUPSPI+bmINTLEVEL+bmGPXB )); //Full-duplex SPI, level interrupt, GPX 219 | MAX3421E_reset(); //stop/start the oscillator 220 | /* configure power switch */ 221 | Vbus_power( OFF ); //turn Vbus power off 222 | MAXreg_wr( rGPINIEN, bmGPINIEN7 ); //enable interrupt on GPIN7 (power switch overload flag) 223 | Vbus_power( ON ); 224 | /* configure host operation */ 225 | MAXreg_wr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST|bmSEPIRQ ); // set pull-downs, SOF, Host, Separate GPIN IRQ on GPX 226 | //MAXreg_wr( rHIEN, bmFRAMEIE|bmCONDETIE|bmBUSEVENTIE ); // enable SOF, connection detection, bus event IRQs 227 | MAXreg_wr( rHIEN, bmCONDETIE ); //connection detection 228 | /* HXFRDNIRQ is checked in Dispatch packet function */ 229 | MAXreg_wr(rHCTL,bmSAMPLEBUS); // update the JSTATUS and KSTATUS bits 230 | MAX_busprobe(); //check if anything is connected 231 | MAXreg_wr( rHIRQ, bmCONDETIRQ ); //clear connection detect interrupt 232 | MAXreg_wr( rCPUCTL, 0x01 ); //enable interrupt pin 233 | } 234 | 235 | /* MAX3421 state change task and interrupt handler */ 236 | void MAX3421E_Task( void ) 237 | { 238 | if( MAX3421E_INT == 0 ) { 239 | MaxIntHandler(); 240 | } 241 | if( MAX3421E_GPX == 1 ) { 242 | MaxGpxHandler(); 243 | } 244 | } 245 | 246 | void MaxIntHandler( void ) 247 | { 248 | BYTE HIRQ; 249 | BYTE HIRQ_sendback = 0x00; 250 | HIRQ = MAXreg_rd( rHIRQ ); //determine interrupt source 251 | // if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler 252 | // HIRQ_sendback |= bmFRAMEIRQ; 253 | // }//end FRAMEIRQ handling 254 | if( HIRQ & bmCONDETIRQ ) { 255 | MAX_busprobe(); 256 | HIRQ_sendback |= bmCONDETIRQ; 257 | } 258 | //if ( HIRQ & bmBUSEVENTIRQ ) { //bus event is either reset or suspend 259 | // usb_task_state++; //advance USB task state machine 260 | // HIRQ_sendback |= bmBUSEVENTIRQ; 261 | //} 262 | /* End HIRQ interrupts handling, clear serviced IRQs */ 263 | MAXreg_wr( rHIRQ, HIRQ_sendback ); 264 | } 265 | void MaxGpxHandler( void ) 266 | { 267 | BYTE GPINIRQ; 268 | 269 | GPINIRQ = MAXreg_rd( rGPINIRQ ); //read both IRQ registers 270 | } 271 | -------------------------------------------------------------------------------- /USB.h: -------------------------------------------------------------------------------- 1 | /* USB task support header */ 2 | 3 | #ifndef _USB_h_ 4 | #define _USB_h_ 5 | 6 | 7 | // ***************************************************************************** 8 | // Section: State Machine Constants 9 | // ***************************************************************************** 10 | 11 | 12 | /* States are defined by 4 high bits 13 | Substates are defined by 4 low bits */ 14 | 15 | 16 | #define USB_STATE_MASK 0xf0 // 17 | #define USB_SUBSTATE_MASK 0x0f // 18 | 19 | #define SUBSUBSTATE_MASK 0x000F // 20 | 21 | #define NEXT_STATE 0x0100 // 22 | #define NEXT_SUBSTATE 0x0010 // 23 | #define NEXT_SUBSUBSTATE 0x0001 // 24 | 25 | #define SUBSUBSTATE_ERROR 0x000F // 26 | 27 | #define NO_STATE 0xFFFF // 28 | 29 | /* 30 | ******************************************************************************* 31 | DETACHED state machine values 32 | 33 | This state machine handles the condition when no device is attached. 34 | */ 35 | 36 | #define USB_STATE_DETACHED 0x00 37 | #define USB_DETACHED_SUBSTATE_INITIALIZE 0x01 38 | #define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x03 39 | #define USB_DETACHED_SUBSTATE_ILLEGAL 0x04 40 | 41 | 42 | /* 43 | ******************************************************************************* 44 | ATTACHED state machine values 45 | 46 | This state machine gets the device descriptor of the remote device. We get the 47 | size of the device descriptor, and use that size to get the entire device 48 | descriptor. Then we check the VID and PID and make sure they appear in the TPL. 49 | */ 50 | 51 | #define USB_STATE_ATTACHED 0x10 52 | #define USB_ATTACHED_SUBSTATE_SETTLE 0x11 53 | #define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x12 54 | #define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x13 55 | #define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x14 56 | #define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x15 57 | //#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR 0x16 58 | //#define USB_ATTACHED_SUBSTATE_VALIDATE_VID_PID 0x17 59 | //#define USB_ATTACHED_SUBSTATE_VALIDATE_CLSP 0x18 60 | 61 | /* 62 | ******************************************************************************* 63 | ADDRESSING state machine values 64 | 65 | This state machine sets the address of the remote device. 66 | */ 67 | 68 | #define USB_STATE_ADDRESSING 0x20 69 | /* 70 | ******************************************************************************* 71 | CONFIGURING state machine values 72 | 73 | This state machine sets the configuration of the remote device, and sets up 74 | internal variables to support the device. 75 | */ 76 | #define USB_STATE_CONFIGURING 0x30 77 | 78 | /* 79 | ******************************************************************************* 80 | RUNNING state machine values 81 | 82 | */ 83 | 84 | #define USB_STATE_RUNNING 0x40 85 | //#define RUNNING_SUBSTATE_NORMAL_RUN 0x0000 // 86 | //#define RUNNING_SUBSTATE_SUSPEND_AND_RESUME 0x0010 // 87 | //#define RUNNING_SUBSUBSTATE_SUSPEND 0x0000 // 88 | //#define RUNNING_SUBSUBSTATE_RESUME 0x0001 // 89 | //#define RUNNING_SUBSUBSTATE_RESUME_WAIT 0x0002 // 90 | //#define RUNNING_SUBSUBSTATE_RESUME_RECOVERY 0x0003 // 91 | //#define RUNNING_SUBSUBSTATE_RESUME_RECOVERY_WAIT 0x0004 // 92 | //#define RUNNING_SUBSUBSTATE_RESUME_COMPLETE 0x0005 // 93 | 94 | 95 | /* 96 | ******************************************************************************* 97 | HOLDING state machine values 98 | 99 | */ 100 | 101 | #define STATE_HOLDING 0x50 // 102 | 103 | #define HOLDING_SUBSTATE_HOLD_INIT 0x0000 // 104 | #define HOLDING_SUBSTATE_HOLD 0x0001 // 105 | 106 | /* Error state machine state. Non-recoverable */ 107 | 108 | #define USB_STATE_ERROR 0xff 109 | 110 | // ***************************************************************************** 111 | // Section: Token State Machine Constants 112 | // ***************************************************************************** 113 | 114 | #define TSTATE_MASK 0x00F0 // 115 | #define TSUBSTATE_MASK 0x000F // 116 | 117 | #define TSUBSTATE_ERROR 0x000F // 118 | 119 | #define TSTATE_IDLE 0x0000 // 120 | 121 | #define TSTATE_CONTROL_NO_DATA 0x0010 // 122 | #define TSUBSTATE_CONTROL_NO_DATA_SETUP 0x0000 // 123 | #define TSUBSTATE_CONTROL_NO_DATA_ACK 0x0001 // 124 | #define TSUBSTATE_CONTROL_NO_DATA_COMPLETE 0x0002 // 125 | 126 | #define TSTATE_CONTROL_READ 0x0020 // 127 | #define TSUBSTATE_CONTROL_READ_SETUP 0x0000 // 128 | #define TSUBSTATE_CONTROL_READ_DATA 0x0001 // 129 | #define TSUBSTATE_CONTROL_READ_ACK 0x0002 // 130 | #define TSUBSTATE_CONTROL_READ_COMPLETE 0x0003 // 131 | 132 | #define TSTATE_CONTROL_WRITE 0x0030 // 133 | #define TSUBSTATE_CONTROL_WRITE_SETUP 0x0000 // 134 | #define TSUBSTATE_CONTROL_WRITE_DATA 0x0001 // 135 | #define TSUBSTATE_CONTROL_WRITE_ACK 0x0002 // 136 | #define TSUBSTATE_CONTROL_WRITE_COMPLETE 0x0003 // 137 | 138 | #define TSTATE_INTERRUPT_READ 0x0040 // 139 | #define TSUBSTATE_INTERRUPT_READ_DATA 0x0000 // 140 | #define TSUBSTATE_INTERRUPT_READ_COMPLETE 0x0001 // 141 | 142 | #define TSTATE_INTERRUPT_WRITE 0x0050 // 143 | #define TSUBSTATE_INTERRUPT_WRITE_DATA 0x0000 // 144 | #define TSUBSTATE_INTERRUPT_WRITE_COMPLETE 0x0001 // 145 | 146 | #define TSTATE_ISOCHRONOUS_READ 0x0060 // 147 | #define TSUBSTATE_ISOCHRONOUS_READ_DATA 0x0000 // 148 | #define TSUBSTATE_ISOCHRONOUS_READ_COMPLETE 0x0001 // 149 | 150 | #define TSTATE_ISOCHRONOUS_WRITE 0x0070 // 151 | #define TSUBSTATE_ISOCHRONOUS_WRITE_DATA 0x0000 // 152 | #define TSUBSTATE_ISOCHRONOUS_WRITE_COMPLETE 0x0001 // 153 | 154 | #define TSTATE_BULK_READ 0x0080 // 155 | #define TSUBSTATE_BULK_READ_DATA 0x0000 // 156 | #define TSUBSTATE_BULK_READ_COMPLETE 0x0001 // 157 | 158 | #define TSTATE_BULK_WRITE 0x0090 // 159 | #define TSUBSTATE_BULK_WRITE_DATA 0x0000 // 160 | #define TSUBSTATE_BULK_WRITE_COMPLETE 0x0001 // 161 | 162 | // ************************ 163 | // Standard USB Requests 164 | #define SR_GET_STATUS 0x00 // Get Status 165 | #define SR_CLEAR_FEATURE 0x01 // Clear Feature 166 | #define SR_RESERVED 0x02 // Reserved 167 | #define SR_SET_FEATURE 0x03 // Set Feature 168 | #define SR_SET_ADDRESS 0x05 // Set Address 169 | #define SR_GET_DESCRIPTOR 0x06 // Get Descriptor 170 | #define SR_SET_DESCRIPTOR 0x07 // Set Descriptor 171 | #define SR_GET_CONFIGURATION 0x08 // Get Configuration 172 | #define SR_SET_CONFIGURATION 0x09 // Set Configuration 173 | #define SR_GET_INTERFACE 0x0a // Get Interface 174 | #define SR_SET_INTERFACE 0x0b // Set Interface 175 | 176 | // Get Descriptor codes 177 | #define GD_DEVICE 0x01 // Get device descriptor: Device 178 | #define GD_CONFIGURATION 0x02 // Get device descriptor: Configuration 179 | #define GD_STRING 0x03 // Get device descriptor: String 180 | #define GD_HID 0x21 // Get descriptor: HID 181 | #define GD_REPORT 0x22 // Get descriptor: Report 182 | 183 | // HID bRequest values 184 | #define GET_REPORT 1 185 | #define GET_IDLE 2 186 | #define GET_PROTOCOL 3 187 | #define SET_REPORT 9 188 | #define SET_IDLE 0x0A 189 | #define SET_PROTOCOL 0x0B 190 | #define INPUT_REPORT 1 191 | 192 | 193 | ////****************************************************************************** 194 | ////****************************************************************************** 195 | //// Section: Macros 196 | //// 197 | //// These macros are all internal to the host layer. 198 | ////****************************************************************************** 199 | ////****************************************************************************** 200 | // 201 | //#define _USB_InitErrorCounters() { numCommandTries = USB_NUM_COMMAND_TRIES; } 202 | //#define _USB_SetDATA01(x) { pCurrentEndpoint->status.bfNextDATA01 = x; } 203 | //#define _USB_SetErrorCode(x) { usbDeviceInfo.errorCode = x; } 204 | //#define _USB_SetHoldState() { usbHostState = STATE_HOLDING; } 205 | //#define _USB_SetNextState() { usbHostState = (usbHostState & STATE_MASK) + NEXT_STATE; } 206 | //#define _host_tasks_SetNextSubState() { host_tasks_state =( host_tasks_state & (STATE_MASK | SUBSTATE_MASK)) + NEXT_SUBSTATE; } 207 | //#define _USB_SetNextSubSubState() { usbHostState = usbHostState + NEXT_SUBSUBSTATE; } 208 | //#define _USB_SetNextTransferState() { pCurrentEndpoint->transferState ++; } 209 | //#define _USB_SetPreviousSubSubState() { usbHostState = usbHostState - NEXT_SUBSUBSTATE; } 210 | //#define _USB_SetTransferErrorState(x) { x->transferState = (x->transferState & TSTATE_MASK) | TSUBSTATE_ERROR; } 211 | //#define freez(x) { free(x); x = NULL; } 212 | 213 | /* data structures */ 214 | 215 | 216 | 217 | 218 | // ***************************************************************************** 219 | /* USB Mass Storage Device Information 220 | 221 | This structure is used to hold all the information about an attached Mass Storage device. 222 | */ 223 | typedef struct _USB_MSD_DEVICE_INFO 224 | { 225 | BYTE blockData[31]; // Data buffer for device communication. 226 | BYTE deviceAddress; // Address of the device on the bus. 227 | BYTE errorCode; // Error code of last error. 228 | BYTE state; // State machine state of the device. 229 | BYTE returnState; // State to return to after performing error handling. 230 | union 231 | { 232 | struct 233 | { 234 | BYTE bfDirection : 1; // Direction of current transfer (0=OUT, 1=IN). 235 | BYTE bfReset : 1; // Flag indicating to perform Mass Storage Reset. 236 | BYTE bfClearDataIN : 1; // Flag indicating to clear the IN endpoint. 237 | BYTE bfClearDataOUT : 1; // Flag indicating to clear the OUT endpoint. 238 | }; 239 | BYTE val; 240 | } flags; 241 | BYTE maxLUN; // The maximum Logical Unit Number of the device. 242 | BYTE interface; // Interface number we are using. 243 | BYTE epin_idx; // Bulk IN endpoint index in devinfo.epinfo_ptr[]. 244 | BYTE epout_idx; // Bulk OUT endpoint index in devinfo.epinfo_ptr[]. 245 | BYTE endpointDATA; // Endpoint to use for the current transfer. 246 | BYTE *userData; // Pointer to the user's data buffer. 247 | DWORD userDataLength; // Length of the user's data buffer. 248 | DWORD bytesTransferred; // Number of bytes transferred to/from the user's data buffer. 249 | DWORD dCBWTag; // The value of the dCBWTag to verify against the dCSWtag. 250 | BYTE attemptsCSW; // Number of attempts to retrieve the CSW. 251 | } USB_MSD_DEVICE_INFO; 252 | 253 | ///* class driver event handler */ 254 | //typedef BOOL (* rom CLASS_EVENT_HANDLER) ( BYTE address, BYTE event, void *data, DWORD size ); 255 | // 256 | ///* class driver initialization */ 257 | //typedef BOOL (* rom CLASS_INIT) ( BYTE address, DWORD flags ); 258 | // 259 | //// ***************************************************************************** 260 | ///* Client Driver Table Structure 261 | // 262 | // */ 263 | // 264 | //typedef struct _CLASS_CALLBACK_TABLE 265 | //{ 266 | // CLASS_INIT Initialize; // Initialization routine 267 | // CLASS_EVENT_HANDLER EventHandler; // Event routine 268 | // DWORD flags; // Initialization flags 269 | // 270 | //} CLASS_CALLBACK_TABLE; 271 | 272 | //* Functions */ 273 | // 274 | //void vUSBtask_init( void ); 275 | //void vUSB_task( void *pvParameters ); 276 | //void prvUSBdata_init( void ); 277 | //char bUSB_Control_Write_ND( BYTE addr, BYTE ep ); 278 | //char bUSB_Control_Read( BYTE addr, BYTE ep ); 279 | //char bUSB_IN_Transfer( BYTE ep, WORD nbytes, BYTE maxpktsize, BYTE * data ); 280 | //char bUSB_Dispatch_Pkt( BYTE token, BYTE ep ); 281 | //BOOL prvMSDInit( BYTE address, DWORD flags ); 282 | //BOOL prvMSDEventHandler( BYTE address, BYTE event, void *data, DWORD size ); 283 | //BOOL prvCDCProbe( BYTE address, DWORD flags ); 284 | //BOOL prvCDCEventHandler( BYTE address, BYTE event, void *data, DWORD size ); 285 | //BOOL prvDummyProbe( BYTE address , DWORD flags ); 286 | //BOOL prvDummyEventHandler( BYTE address, BYTE event, void *data, DWORD size ); 287 | //BYTE flush_Q( xQueueHandle QueueH ); 288 | 289 | 290 | #endif //_USB_h_ -------------------------------------------------------------------------------- /transfer.h: -------------------------------------------------------------------------------- 1 | /* USB transfers support header */ 2 | 3 | #ifndef _transfer_h_ 4 | #define _transfer_h_ 5 | 6 | /* Targeted peripheral list table */ 7 | #define USB_NUMTARGETS 4 //number of targets in TPL, not counting uninitialized device 8 | #define USB_NUMDEVICES 8 //number of supported devices 9 | #define USB_NUMCLASSES 4 //number of device classes in class callback table 10 | #define UNINIT 0 //uninitialized 11 | #define HID_K 1 //HID Keyboard boot driver number in DEV_RECORD 12 | #define HID_M 2 //HID Mouse boot driver number in DEV_RECORD 13 | #define MSD 3 //Mass storage class driver number in DEV_RECORD 14 | 15 | 16 | /* Standard Device Requests */ 17 | 18 | #define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS 19 | #define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE 20 | #define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE 21 | #define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS 22 | #define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR 23 | #define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR 24 | #define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION 25 | #define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION 26 | #define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE 27 | #define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE 28 | #define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME 29 | 30 | #define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt 31 | #define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up 32 | #define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode 33 | 34 | /* Setup Data Constants */ 35 | 36 | #define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer 37 | #define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer 38 | #define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard 39 | #define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class 40 | #define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor 41 | #define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device 42 | #define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface 43 | #define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint 44 | #define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other 45 | 46 | /* USB descriptors */ 47 | 48 | #define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor. 49 | #define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor. 50 | #define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor. 51 | #define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor. 52 | #define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor. 53 | #define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier. 54 | #define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration. 55 | #define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power. 56 | #define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor. 57 | 58 | /* OTG SET FEATURE Constants */ 59 | #define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP 60 | #define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP 61 | #define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP 62 | 63 | /* USB Endpoint Transfer Types */ 64 | #define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint. 65 | #define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint. 66 | #define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint. 67 | #define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint. 68 | #define bmUSB_TRANSFER_TYPE 0x03 // bit mask to separate transfer type from ISO attributes 69 | 70 | 71 | /* Standard Feature Selectors for CLEAR_FEATURE Requests */ 72 | #define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient 73 | #define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient 74 | #define USB_FEATURE_TEST_MODE 2 // Device recipient 75 | 76 | /* MSD class requests. Not part of chapter 9 */ 77 | #define USB_MSD_GET_MAX_LUN 0xFE // Device Request code to get the maximum LUN. 78 | #define USB_MSD_RESET 0xFF // Device Request code to reset the device. 79 | 80 | /* HID constants. Not part of chapter 9 */ 81 | /* Class-Specific Requests */ 82 | #define HID_REQUEST_GET_REPORT 0x01 83 | #define HID_REQUEST_GET_IDLE 0x02 84 | #define HID_REQUEST_GET_PROTOCOL 0x03 85 | #define HID_REQUEST_SET_REPORT 0x09 86 | #define HID_REQUEST_SET_IDLE 0x0A 87 | #define HID_REQUEST_SET_PROTOCOL 0x0B 88 | 89 | /* Class Descriptor Types */ 90 | #define HID_DESCRIPTOR_HID 0x21 91 | #define HID_DESCRIPTOR_REPORT 0x22 92 | #define HID_DESRIPTOR_PHY 0x23 93 | 94 | /* Protocol Selection */ 95 | #define BOOT_PROTOCOL 0x00 96 | #define RPT_PROTOCOL 0x01 97 | /* HID Interface Class Code */ 98 | #define HID_INTF 0x03 99 | /* HID Interface Class SubClass Codes */ 100 | #define BOOT_INTF_SUBCLASS 0x01 101 | /* HID Interface Class Protocol Codes */ 102 | #define HID_PROTOCOL_NONE 0x00 103 | #define HID_PROTOCOL_KEYBOARD 0x01 104 | #define HID_PROTOCOL_MOUSE 0x02 105 | 106 | 107 | 108 | 109 | /* USB Setup Packet Structure */ 110 | typedef struct { 111 | union { // offset description 112 | BYTE bmRequestType; // 0 Bit-map of request type 113 | struct { 114 | BYTE recipient: 5; // Recipient of the request 115 | BYTE type: 2; // Type of request 116 | BYTE direction: 1; // Direction of data X-fer 117 | }; 118 | }ReqType_u; 119 | BYTE bRequest; // 1 Request 120 | union { 121 | WORD wValue; // 2 Depends on bRequest 122 | struct { 123 | BYTE wValueLo; 124 | BYTE wValueHi; 125 | }; 126 | }wVal_u; 127 | WORD wIndex; // 4 Depends on bRequest 128 | WORD wLength; // 6 Depends on bRequest 129 | } SETUP_PKT, *PSETUP_PKT; 130 | 131 | /* Endpoint information structure */ 132 | /* bToggle of endpoint 0 initialized to 0xff */ 133 | /* during enumeration bToggle is set to 00 */ 134 | typedef struct { 135 | BYTE epAddr; //copy from endpoint descriptor. Bit 7 indicates direction ( ignored for control endpoints ) 136 | BYTE Attr; // Endpoint transfer type. 137 | WORD MaxPktSize; // Maximum packet size. 138 | BYTE Interval; // Polling interval in frames. 139 | BYTE sndToggle; //last toggle value, bitmask for HCTL toggle bits 140 | BYTE rcvToggle; //last toggle value, bitmask for HCTL toggle bits 141 | /* not sure if both are necessary */ 142 | } EP_RECORD; 143 | /* device record structure */ 144 | typedef struct { 145 | EP_RECORD* epinfo; //device endpoint information 146 | BYTE devclass; //device class 147 | } DEV_RECORD; 148 | 149 | 150 | /* targeted peripheral list element */ 151 | typedef struct { 152 | union { 153 | DWORD val; 154 | struct { 155 | WORD idVendor; 156 | WORD idProduct; 157 | }; 158 | struct { 159 | BYTE bClass; 160 | BYTE bSubClass; 161 | BYTE bProtocol; 162 | }; 163 | }dev_u; 164 | BYTE bConfig; //configuration 165 | BYTE numep; //number of endpoints 166 | EP_RECORD* epinfo; //endpoint information structure 167 | BYTE CltDrv; //client driver 168 | const rom char * desc; //device description 169 | }USB_TPL_ENTRY; 170 | /* control transfer */ 171 | typedef BYTE (* CTRL_XFER )( BYTE addr, BYTE ep, WORD nbytes, char* dataptr, BOOL direction ); 172 | /* class driver initialization */ 173 | typedef BOOL (* rom CLASS_INIT)( BYTE address, DWORD flags ); 174 | /* class driver event handler */ 175 | typedef BOOL (* rom CLASS_EVENT_HANDLER)( BYTE address, BYTE event, void *data, DWORD size ); 176 | /* Client Driver Table Structure */ 177 | typedef struct { 178 | CLASS_INIT Initialize; // Initialization routine 179 | CLASS_EVENT_HANDLER EventHandler; // Event routine 180 | DWORD flags; // Initialization flags 181 | } CLASS_CALLBACK_TABLE; 182 | 183 | /* Common setup data constant combinations */ 184 | #define bmREQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type 185 | #define bmREQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface' 186 | #define bmREQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type 187 | 188 | #define bmREQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE 189 | #define bmREQ_HIDIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE 190 | 191 | /* Function macros */ 192 | 193 | //char XferCtrlReq( BYTE addr, BYTE ep, BYTE bmReqType, BYTE bRequest, BYTE wValLo, BYTE wValHi, WORD wInd, WORD nbytes, char* dataptr ) 194 | 195 | /* Set address request macro. Human-readable form of bXferCtrlReq */ 196 | /* won't necessarily work for device in 'Configured' state */ 197 | #define XferSetAddr( oldaddr, ep, newaddr ) \ 198 | XferCtrlReq( oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL ) 199 | /* Set Configuration Request */ 200 | #define XferSetConf( addr, ep, conf_value ) \ 201 | XferCtrlReq( addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL ) 202 | ///* Get configuration request */ 203 | //#define bXferGetConf( addr, ep, urb_ptr ) bXferCtrlReq( addr, ep, 1, ( bmREQ_GET_DESCR ), USB_REQUEST_GET_CONFIGURATION, 0x00, 0x00, 0x00, urb_ptr ); 204 | /* Get device descriptor request macro */ 205 | #define XferGetDevDescr( addr, ep, nbytes, dataptr ) \ 206 | XferCtrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr ) 207 | ///* Get configuration descriptor request macro */ 208 | #define XferGetConfDescr( addr, ep, nbytes, conf, dataptr ) \ 209 | XferCtrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr ) 210 | ///* Get string descriptor request macro */ 211 | //#define bXferGetStrDescr( addr, ep, nbytes, index, langid, urb_ptr ) bXferCtrlReq( addr, ep, nbytes, ( bmREQ_GET_DESCR ), USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, urb_ptr ) 212 | ///* Get MAX LUN MSD class request macro */ 213 | //#define bXferGetMaxLUN( addr, intf, urb_ptr ) bXferCtrlReq( addr, 0, 1, ( bmREQ_CL_GET_INTF ), USB_MSD_GET_MAX_LUN, 0, 0, intf, urb_ptr ) 214 | /* class requests */ 215 | #define XferSetProto( addr, ep, interface, protocol ) \ 216 | XferCtrlReq( addr, ep, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, interface, 0x0000, NULL ) 217 | #define XferGetProto( addr, ep, interface, dataptr ) \ 218 | XferCtrlReq( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, interface, 0x0001, dataptr ) 219 | #define XferGetIdle( addr, ep, interface, reportID, dataptr ) \ 220 | XferCtrlReq( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, interface, 0x0001, dataptr ) 221 | 222 | 223 | 224 | /* Function prototypes */ 225 | 226 | BYTE XferCtrlReq( BYTE addr, BYTE ep, BYTE bmReqType, BYTE bRequest, BYTE wValLo, BYTE wValHi, WORD wInd, WORD nbytes, char* dataptr ); 227 | BYTE XferCtrlData( BYTE addr, BYTE ep, WORD nbytes, char* dataptr, BOOL direction ); 228 | BYTE XferCtrlND( BYTE addr, BYTE ep, WORD nbytes, char* dataptr, BOOL direction ); 229 | //BYTE startCtrlReq( BYTE addr, BYTE ep, BYTE bmReqType, BYTE bRequest, BYTE wValLo, BYTE wValHi, WORD wInd, WORD nbytes, char* dataptr ); 230 | BYTE XferDispatchPkt( BYTE token, BYTE ep ); 231 | BYTE XferInTransfer( BYTE addr, BYTE ep, WORD nbytes, char* data, BYTE maxpktsize ); 232 | //BYTE XferInTransfer_mps( BYTE ep, char* data, BYTE maxpktsize ); 233 | void USB_init( void ); 234 | void USB_Task( void ); 235 | BYTE GetUsbTaskState( void ); 236 | DEV_RECORD* GetDevtable( BYTE index ); 237 | 238 | /* Client driver routines */ 239 | BOOL MSDProbe( BYTE address, DWORD flags ); 240 | BOOL MSDEventHandler( BYTE address, BYTE event, void *data, DWORD size ); 241 | BOOL CDCProbe( BYTE address, DWORD flags ); 242 | BOOL CDCEventHandler( BYTE address, BYTE event, void *data, DWORD size ); 243 | BOOL DummyProbe( BYTE address , DWORD flags ); 244 | BOOL DummyEventHandler( BYTE address, BYTE event, void *data, DWORD size ); 245 | 246 | 247 | #endif //_transfer_h_ -------------------------------------------------------------------------------- /transfer.c: -------------------------------------------------------------------------------- 1 | /* USB transfers */ 2 | 3 | 4 | #define _transfer_c_ 5 | 6 | #include "project_config.h" 7 | 8 | EP_RECORD dev0ep = {{ 0 }}; //Endpoint data structure for uninitialized device during enumeration 9 | EP_RECORD msd_ep[ 3 ] = {{ 0 }}; //Mass storage bulk-only transport endpoints: 1 control and 2 bulk, IN and OUT 10 | //ep records for other classes are defined in class-specific modules 11 | 12 | /* macros to aid filling in TPL */ 13 | #define INIT_VID_PID(v,p) 0x##p##v 14 | #define INIT_CL_SC_P(c,s,p) 0x##00##p##s##c 15 | 16 | //const rom USB_TPL_ENTRY TplTable[ USB_NUMTARGETS + 1 ] = { 17 | //// VID & PID or Client 18 | //// Class, Subclass & Protocol Config Numep Eprecord Driver 19 | //{ INIT_VID_PID( 0000, 0000 ), 0, 1, &dev0ep, 0, "Uninitialized" }, 20 | //{ INIT_VID_PID( 0781, 5406 ), 0, 3, msd_ep, MSD_DRIVER, "Mass storage" }, //Sandisk U3 Cruzer Micro 21 | ////{ INIT_VID_PID( 0CF2, 6220 ), 0, 0 }, //ENE UB6220 22 | //{ INIT_CL_SC_P( 03, 01, 02 ), 0, 3, hid_ep, HIDM_DRIVER, "HID Mouse with Boot protocol" }, // 23 | //{ INIT_VID_PID( aaaa, 5555 ), 0, 1, NULL, 0, NULL }, // 24 | //{ INIT_CL_SC_P( 08, 06, 50 ), 0, 3, msd_ep, MSD_DRIVER, "Mass storage" } //Mass storage bulk only class 25 | //}; 26 | 27 | /* control transfers function pointers */ 28 | const rom CTRL_XFER ctrl_xfers[ 2 ] = { 29 | XferCtrlND, 30 | XferCtrlData 31 | }; 32 | 33 | /* device table. Filled during enumeration */ 34 | /* index corresponds to device address */ 35 | /* each entry contains pointer to endpoint structure */ 36 | /* and device class to use in various places */ 37 | DEV_RECORD devtable[ USB_NUMDEVICES + 1 ]; 38 | 39 | /* Client Driver Function Pointer Table */ 40 | CLASS_CALLBACK_TABLE ClientDriverTable[ USB_NUMCLASSES ] = { 41 | { 42 | MSDProbe, //Mass storage class device init 43 | MSDEventHandler, 44 | 0 45 | }, 46 | { 47 | HIDMProbe, //HID class device init 48 | HIDMEventHandler, 49 | 0 50 | }, 51 | { 52 | HIDKProbe, 53 | HIDKEventHandler, 54 | 0 55 | }, 56 | { 57 | DummyProbe, 58 | DummyEventHandler, 59 | 0 60 | } 61 | }; 62 | /* Control transfer stages function pointer table */ 63 | 64 | 65 | /* USB state machine related variables */ 66 | 67 | BYTE usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; 68 | BYTE usb_error; 69 | BYTE last_usb_task_state = 0; 70 | 71 | /* external variables */ 72 | extern DWORD uptime; 73 | 74 | /* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */ 75 | /* depending on request. Actual requests are defined as macros */ 76 | /* return codes: */ 77 | /* 00 = success */ 78 | /* 01-0f = non-zero HRSLT */ 79 | BYTE XferCtrlReq( BYTE addr, BYTE ep, BYTE bmReqType, BYTE bRequest, BYTE wValLo, BYTE wValHi, WORD wInd, WORD nbytes, char* dataptr ) 80 | { 81 | BOOL direction = FALSE; //request direction, IN or OUT 82 | BYTE datastage = 1; //request data stage present or absent 83 | BYTE rcode; 84 | SETUP_PKT setup_pkt; 85 | if( dataptr == NULL ) { 86 | datastage = 0; 87 | } 88 | MAXreg_wr( rPERADDR, addr ); //set peripheral address 89 | /* fill in setup packet */ 90 | if( bmReqType & 0x80 ) { 91 | direction = TRUE; //determine request direstion 92 | } 93 | /* fill in setup packet */ 94 | setup_pkt.ReqType_u.bmRequestType = bmReqType; 95 | setup_pkt.bRequest = bRequest; 96 | setup_pkt.wVal_u.wValueLo = wValLo; 97 | setup_pkt.wVal_u.wValueHi = wValHi; 98 | setup_pkt.wIndex = wInd; 99 | setup_pkt.wLength = nbytes; 100 | MAXbytes_wr( rSUDFIFO, 8, (BYTE *)&setup_pkt ); //transfer to setup packet FIFO 101 | rcode = XferDispatchPkt( tokSETUP, ep ); //dispatch packet 102 | if( rcode ) { //return HRSLT if not zero 103 | return( rcode ); 104 | } 105 | rcode = ctrl_xfers[ datastage ]( addr, ep, nbytes, dataptr, direction ); //call data stage or no data stage transfer 106 | return( rcode ); 107 | } 108 | /* Control transfer with data stage */ 109 | BYTE XferCtrlData( BYTE addr, BYTE ep, WORD nbytes, char* dataptr, BOOL direction ) 110 | { 111 | BYTE rcode; 112 | 113 | //MAXreg_wr( rHCTL, bmRCVTOG1 ); //set toggle to DATA1 114 | if( direction ) { //IN transfer 115 | devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1; 116 | rcode = XferInTransfer( addr, ep, nbytes, dataptr, devtable[ addr ].epinfo[ ep ].MaxPktSize ); 117 | if( rcode ) { 118 | return( rcode ); 119 | } 120 | rcode = XferDispatchPkt( tokOUTHS, ep ); 121 | return( rcode ); 122 | } 123 | else { //OUT not implemented 124 | return( 0xff ); 125 | } 126 | } 127 | /* Control transfer with status stage and no data stage */ 128 | BYTE XferCtrlND( BYTE addr, BYTE ep, WORD nbytes, char* dataptr, BOOL direction ) 129 | { 130 | BYTE rcode; 131 | if( direction ) { //GET 132 | rcode = XferDispatchPkt( tokOUTHS, ep ); 133 | } 134 | else { 135 | rcode = XferDispatchPkt( tokINHS, ep ); 136 | } 137 | return( rcode ); 138 | } 139 | /* Dispatch a packet. Assumes peripheral address is set and, if necessary, sudFIFO-sendFIFO loaded. */ 140 | /* Result code: 0 success, nonzero = error condition */ 141 | /* If NAK, tries to re-send up to USB_NAK_LIMIT times */ 142 | /* If bus timeout, re-sends up to USB_RETRY_LIMIT times */ 143 | /* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout */ 144 | BYTE XferDispatchPkt( BYTE token, BYTE ep ) 145 | { 146 | DWORD timeout = uptime + USB_XFER_TIMEOUT; 147 | BYTE tmpdata; 148 | BYTE rcode; 149 | char retry_count = 0; 150 | BYTE nak_count = 0; 151 | 152 | while( 1 ) { 153 | MAXreg_wr( rHXFR, ( token|ep )); //launch the transfer 154 | rcode = 0xff; 155 | while( uptime < timeout ) { 156 | tmpdata = MAXreg_rd( rHIRQ ); 157 | if( tmpdata & bmHXFRDNIRQ ) { 158 | MAXreg_wr( rHIRQ, bmHXFRDNIRQ ); //clear the interrupt 159 | rcode = 0x00; 160 | break; 161 | } 162 | } 163 | if( rcode != 0x00 ) { //exit if timeout 164 | return( rcode ); 165 | } 166 | rcode = ( MAXreg_rd( rHRSL ) & 0x0f ); 167 | if( rcode == hrNAK ) { 168 | nak_count++; 169 | if( nak_count == USB_NAK_LIMIT ) { 170 | break; 171 | } 172 | else { 173 | continue; 174 | } 175 | } 176 | if( rcode == hrTIMEOUT ) { 177 | retry_count++; 178 | if( retry_count == USB_RETRY_LIMIT ) { 179 | break; 180 | } 181 | else { 182 | continue; 183 | } 184 | } 185 | else break; 186 | }//while( 1 ) 187 | return( rcode ); 188 | } 189 | /* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. 190 | Keep sending INs and writes data to memory area pointed by 'data' */ 191 | /* rcode 0 if no errors. rcode 01-0f is relayed from prvXferDispatchPkt(). Rcode f0 means RCVDAVIRQ error, 192 | fe USB xfer timeout */ 193 | BYTE XferInTransfer( BYTE addr/* not sure if it's necessary */, BYTE ep, WORD nbytes, char* data, BYTE maxpktsize ) 194 | { 195 | BYTE rcode; 196 | BYTE i; 197 | BYTE tmpbyte; 198 | BYTE pktsize; 199 | WORD xfrlen = 0; 200 | MAXreg_wr( rHCTL, devtable[ addr ].epinfo[ ep ].rcvToggle ); //set toggle value 201 | while( 1 ) { // use a 'return' to exit this loop 202 | rcode = XferDispatchPkt( tokIN, ep ); //IN packet to EP-'endpoint'. Function takes care of NAKS. 203 | if( rcode ) { 204 | return( rcode ); //should be 0, indicating ACK. Else return error code. 205 | } 206 | /* check for RCVDAVIRQ and generate error if not present */ 207 | /* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */ 208 | if(( MAXreg_rd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) { 209 | return ( 0xf0 ); //receive error 210 | } 211 | pktsize = MAXreg_rd( rRCVBC ); //number of received bytes 212 | data = MAXbytes_rd( rRCVFIFO, pktsize, data ); 213 | MAXreg_wr( rHIRQ, bmRCVDAVIRQ ); // Clear the IRQ & free the buffer 214 | xfrlen += pktsize; // add this packet's byte count to total transfer length 215 | /* The transfer is complete under two conditions: */ 216 | /* 1. The device sent a short packet (L.T. maxPacketSize) */ 217 | /* 2. 'nbytes' have been transferred. */ 218 | if (( pktsize < maxpktsize ) || (xfrlen >= nbytes )) { // have we transferred 'nbytes' bytes? 219 | if( MAXreg_rd( rHRSL ) & bmRCVTOGRD ) { //save toggle value 220 | devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1; 221 | } 222 | else { 223 | devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG0; 224 | } 225 | return( 0 ); 226 | } 227 | }//while( 1 ) 228 | } 229 | /* initialization of USB data structures */ 230 | void USB_init( void ) 231 | { 232 | BYTE i; 233 | for( i = 0; i < ( USB_NUMDEVICES + 1 ); i++ ) { 234 | devtable[ i ].epinfo = NULL; //clear device table 235 | devtable[ i ].devclass = 0; 236 | } 237 | devtable[ 0 ].epinfo = &dev0ep; //set single ep for uninitialized device 238 | dev0ep.MaxPktSize = 0; 239 | dev0ep.sndToggle = bmSNDTOG0; //set DATA0/1 toggles to 0 240 | dev0ep.rcvToggle = bmRCVTOG0; 241 | } 242 | /* USB state machine. Connect/disconnect, enumeration, initialization */ 243 | /* error codes: 01-0f HRSLT */ 244 | /* ff - unsupported device */ 245 | /* fe - no address available */ 246 | /* fd - no client driver available */ 247 | void USB_Task( void ) 248 | { 249 | static DWORD usb_delay = 0; 250 | static BYTE tmp_addr; 251 | USB_DEVICE_DESCRIPTOR buf; 252 | 253 | BYTE rcode, tmpdata; 254 | char i; 255 | 256 | switch( usb_task_state & USB_STATE_MASK ) { 257 | /* Detached state - when nothing is connected to ( or just disconnected from) USB bus */ 258 | case( USB_STATE_DETACHED ): 259 | switch( usb_task_state ) { 260 | case( USB_DETACHED_SUBSTATE_INITIALIZE ): 261 | /* cleanup device data structures */ 262 | USB_init(); 263 | usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE; 264 | break; 265 | case( USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE ): 266 | /* Do nothing */ 267 | MAXreg_wr(rHCTL,bmSAMPLEBUS); 268 | break; 269 | case( USB_DETACHED_SUBSTATE_ILLEGAL ): 270 | /* don't know what to do yet */ 271 | break; 272 | }//switch( usb_task_state ) 273 | break;//( USB_STATE_DETACHED ): 274 | /**/ 275 | case( USB_STATE_ATTACHED ): //prepare for enumeration 276 | switch( usb_task_state ) { 277 | case( USB_STATE_ATTACHED ): 278 | usb_delay = uptime + 200; //initial settle 200ms 279 | usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE; 280 | break;//case( USB_STATE_ATTACHED ) 281 | case( USB_ATTACHED_SUBSTATE_SETTLE ): //waiting for settle timer to expire 282 | if( uptime > usb_delay ) { 283 | usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE; 284 | } 285 | break;//case( USB_ATTACHED_SUBSTATE_SETTLE ) 286 | case( USB_ATTACHED_SUBSTATE_RESET_DEVICE ): 287 | MAXreg_wr( rHIRQ, bmBUSEVENTIRQ ); //clear bus event IRQ 288 | MAXreg_wr( rHCTL, bmBUSRST ); //issue bus reset 289 | usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE; 290 | break;//case( USB_ATTACHED_SUBSTATE_RESET_DEVICE ) 291 | case( USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE ): //wait for bus reset and first SOF 292 | if(( MAXreg_rd( rHCTL ) & bmBUSRST ) == 0 ) { 293 | tmpdata = MAXreg_rd( rMODE ) | bmSOFKAENAB; //start SOF generation 294 | MAXreg_wr( rMODE, tmpdata ); 295 | usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF; 296 | } 297 | break;//case( USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE ) 298 | case( USB_ATTACHED_SUBSTATE_WAIT_SOF ): 299 | if( MAXreg_rd( rHIRQ ) | bmFRAMEIRQ ) { //when first SOF received we can continue 300 | usb_task_state = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE; 301 | } 302 | break;//case( USB_ATTACHED_SUBSTATE_WAIT_SOF ) 303 | case( USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE ): //send request for first 8 bytes of device descriptor 304 | devtable[ 0 ].epinfo->MaxPktSize = 0x0008; //fill max packet size with minimum allowed 305 | rcode = XferGetDevDescr( 0, 0, 8, (char *)&buf ); //get device descriptor size 306 | if( rcode == 0 ) { 307 | devtable[ 0 ].epinfo->MaxPktSize = buf.bMaxPacketSize0; 308 | usb_task_state = USB_STATE_ADDRESSING; 309 | } 310 | else { 311 | usb_error = rcode; 312 | last_usb_task_state = usb_task_state; 313 | usb_task_state = USB_STATE_ERROR; 314 | } 315 | break;//case( USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE ): 316 | }//switch( usb_task_state ) 317 | break;//case ( USB_STATE_ATTACHED ) 318 | case( USB_STATE_ADDRESSING ): //give device an address 319 | for( i = 1; i < USB_NUMDEVICES; i++ ) { 320 | if( devtable[ i ].epinfo == NULL ) { 321 | devtable[ i ].epinfo = devtable[ 0 ].epinfo; //set correct MaxPktSize 322 | //devtable[ i ].epinfo->MaxPktSize = devtable[ 0 ].epinfo->MaxPktSize; //copy unitialized device record to have correct MaxPktSize 323 | rcode = XferSetAddr( 0, 0, i ); 324 | if( rcode == 0 ) { 325 | tmp_addr = i; 326 | usb_task_state = USB_STATE_CONFIGURING; 327 | } 328 | else { 329 | usb_error = rcode; //set address error 330 | last_usb_task_state = usb_task_state; 331 | usb_task_state = USB_STATE_ERROR; 332 | } 333 | break; //break if address assigned or error occured during address assignment attempt 334 | } 335 | } 336 | if( usb_task_state == USB_STATE_ADDRESSING ) { 337 | usb_error = 0xfe; 338 | last_usb_task_state = usb_task_state; 339 | usb_task_state = USB_STATE_ERROR; 340 | } 341 | break;//case ( USB_STATE_ADDRESSING ) 342 | case( USB_STATE_CONFIGURING ): //checking for driver 343 | /* run device class probes until one returns TRUE */ 344 | for( i = 0; i < USB_NUMCLASSES; i++ ) { 345 | rcode = ClientDriverTable[ i ].Initialize( tmp_addr, 0 ); 346 | if( rcode == TRUE ) { 347 | usb_task_state = USB_STATE_RUNNING; 348 | break; 349 | } 350 | } 351 | if( usb_task_state == USB_STATE_CONFIGURING ) { 352 | usb_error = 0xfd; 353 | last_usb_task_state = usb_task_state; 354 | usb_task_state = USB_STATE_ERROR; 355 | } 356 | break;//( USB_STATE_CONFIGURING ) 357 | case( USB_STATE_RUNNING ): 358 | //vTaskDelay( LED_RATE ); 359 | break;//( USB_STATE_RUNNING ) 360 | case( USB_STATE_ERROR ): 361 | //vTaskDelay( LED_RATE ); //stay here if error 362 | break;//( USB_STATE_ERROR ) 363 | default: 364 | //Should never get here 365 | break; 366 | }//switch( usb_task_state & STATE_MASK ) 367 | } 368 | /* returns TRUE if device is successfuly identified and configured, otherwise returns FALSE */ 369 | BOOL MSDProbe( BYTE addr, DWORD flags ) 370 | { 371 | return( FALSE ); 372 | } 373 | 374 | BOOL MSDEventHandler( BYTE address, BYTE event, void *data, DWORD size ) 375 | { 376 | 377 | return( FALSE ); 378 | 379 | } 380 | 381 | BOOL CDCProbe( BYTE address, DWORD flags ) 382 | { 383 | 384 | return( FALSE ); 385 | 386 | } 387 | 388 | BOOL CDCEventHandler( BYTE address, BYTE event, void *data, DWORD size ) 389 | { 390 | return( FALSE ); 391 | } 392 | 393 | BOOL DummyProbe( BYTE address , DWORD flags ) 394 | { 395 | return( FALSE ); 396 | } 397 | 398 | BOOL DummyEventHandler( BYTE address, BYTE event, void *data, DWORD size ) 399 | { 400 | return( FALSE ); 401 | } 402 | /* Function to access usb_task_state variable from outside */ 403 | BYTE GetUsbTaskState( void ) 404 | { 405 | return( usb_task_state ); 406 | } 407 | /* Function to access devtable[] from outside */ 408 | DEV_RECORD* GetDevtable( BYTE index ) 409 | { 410 | return( &devtable[ index ] ); 411 | } -------------------------------------------------------------------------------- /cli.c: -------------------------------------------------------------------------------- 1 | /* CLI functions */ 2 | 3 | #define _CLI_C_ 4 | 5 | #include 6 | #include "project_config.h" 7 | #include "cli_constants.h" 8 | 9 | extern DWORD uptime; 10 | extern HID_DEVICE hid_device; 11 | extern DEV_RECORD devtable[]; 12 | 13 | 14 | #define NUM_MENUS 6 //number of top-level menus 15 | /* menu position in function pointer array */ 16 | static enum { 17 | CLI_MAIN_MENU = 0, 18 | CLI_SHOW_MENU = 1, 19 | CLI_SET_MENU = 2, 20 | CLI_USBQ_MENU = 3, 21 | CLI_USBT_MENU = 4, 22 | CLI_UTIL_MENU = 5 23 | } cli_state = CLI_MAIN_MENU; //CLI states 24 | /* array of function pointers to top-level menus */ 25 | static void ( * const rom top_menu[ NUM_MENUS ] )( void ) = { 26 | CLI_main_menu, 27 | CLI_show_menu, 28 | CLI_set_menu, 29 | CLI_usbq_menu, 30 | CLI_usbt_menu, 31 | CLI_util_menu 32 | }; 33 | 34 | char bigbuf[ 256 ]; 35 | static BYTE devaddr = 1; //temporary assignment for the only device supported atm 36 | 37 | /* Local prototypes */ 38 | BOOL prevCodeComp( BYTE data, BOOT_KBD_REPORT* buf ); 39 | BYTE HIDtoa( BOOT_KBD_REPORT* buf, BYTE index ); 40 | 41 | 42 | /* CLI main loop state machine */ 43 | void CLI_Task( void ) 44 | { 45 | top_menu[ cli_state ](); //call top-level menu according to current state 46 | return; 47 | } 48 | 49 | /* root level CLI */ 50 | /* switches state to next level menus */ 51 | void CLI_main_menu( void ) 52 | { 53 | BYTE temp; 54 | 55 | if(!CharInQueue()) { 56 | return; 57 | } 58 | temp = recvchar(); 59 | if ( temp > 0x1f ) { 60 | sendchar( temp ); //echo back 61 | } 62 | switch( temp ) { 63 | case( 0x0d ): //"Enter" 64 | send_string(cli_prompt_main); 65 | break; 66 | case( 0x1b ): //"ESC" 67 | cli_state = CLI_MAIN_MENU; 68 | send_string(cli_prompt_main); 69 | break; 70 | case( 0x31 ): //"1 - show menu" 71 | cli_state = CLI_SHOW_MENU; 72 | send_string(cli_prompt_show); 73 | break; 74 | case( 0x32 ): //"2 - set menu" 75 | cli_state = CLI_SET_MENU; 76 | send_string(cli_prompt_set); 77 | break; 78 | case( 0x33 ): //"3 - USB queries menu" 79 | cli_state = CLI_USBQ_MENU; 80 | send_string(cli_prompt_usbq); 81 | break; 82 | case( 0x34 ): //"4 - USB transfers menu" 83 | cli_state = CLI_USBT_MENU; 84 | send_string(cli_prompt_usbt); 85 | break; 86 | case( 0x35 ): //"5 - Utilities menu" 87 | cli_state = CLI_UTIL_MENU; 88 | send_string(cli_prompt_util); 89 | break; 90 | case( 0x3f ): //Question mark 91 | send_string(cli_root_menu_help); 92 | send_string(cli_prompt_main); 93 | break; 94 | default: 95 | send_string(cli_invalid_key); 96 | send_string(cli_prompt_main); 97 | break; 98 | } //end switch( temp ) 99 | } 100 | 101 | /* show level CLI */ 102 | /* state CLI_SHOW_MENU */ 103 | void CLI_show_menu( void ) 104 | { 105 | BYTE i; 106 | BYTE temp; 107 | DEV_RECORD* tpl_ptr; 108 | if(!CharInQueue()) { 109 | return; 110 | } 111 | temp = recvchar(); 112 | if ( temp > 0x1f ) { 113 | sendchar( temp ); //echo back 114 | } 115 | switch( temp ) { 116 | case( 0x0d ): //"Enter" 117 | send_string(cli_prompt_show); 118 | break; 119 | case( 0x1b ): //"ESC" 120 | cli_state = CLI_MAIN_MENU; //change state to "Main" 121 | send_string(cli_prompt_main); 122 | break; 123 | case( 0x31 ): //"1 - print MAX3421E registers" 124 | i = 0; 125 | while( register_format[ i ].name != NULL ) { 126 | send_string( register_format[i].name ); 127 | send_hexbyte( MAXreg_rd( register_format[i].number )); 128 | i++; 129 | } 130 | send_string(cli_prompt_show); 131 | break; 132 | case( 0x32 ): //2 - Print USB task state 133 | send_string("\r\nUSB task state: "); 134 | send_hexbyte( GetUsbTaskState()); 135 | send_string(cli_prompt_show); 136 | break; 137 | case( 0x33 ): //3 - Print device table 138 | for( i = 1; i < USB_NUMDEVICES; i++ ) { 139 | tpl_ptr = GetDevtable( i ); 140 | if( tpl_ptr->epinfo != NULL ) { 141 | send_string( crlf ); 142 | send_string("Device: "); 143 | send_decword( i ); 144 | send_string( devclasses[ tpl_ptr->devclass ] ); 145 | send_string( crlf ); 146 | } 147 | }//for( i = 1; i < USB_NUMDEVICES; i++ 148 | send_string(cli_prompt_show); 149 | break; 150 | case( 0x3f ): //Question mark 151 | send_string(cli_show_menu_help); 152 | send_string(esc_prev_lvl); 153 | send_string(cli_prompt_show); 154 | break; 155 | default: 156 | send_string(cli_invalid_key); 157 | send_string(cli_prompt_show); 158 | break; 159 | } //end switch( temp ) 160 | } 161 | 162 | /* SET level CLI */ 163 | /* state CLI_SET_MENU */ 164 | void CLI_set_menu( void ) 165 | { 166 | BYTE temp; 167 | BYTE rcode; 168 | if(!CharInQueue()) { 169 | return; 170 | } 171 | temp = recvchar(); 172 | if ( temp > 0x1f ) { 173 | sendchar( temp ); //echo back 174 | } 175 | switch( temp ) { 176 | case( 0x0d ): //"Enter" 177 | send_string(cli_prompt_set); 178 | break; 179 | case( 0x1b ): //"ESC" 180 | cli_state = CLI_MAIN_MENU; //change state to "Main" 181 | send_string(cli_prompt_main); 182 | break; 183 | case( 0x31 ): //"1" - reset MAX3421E 184 | MAX3421E_reset(); 185 | send_string ("\r\nMAX3421E reset\r\n"); 186 | break; 187 | case( 0x32 ): //"2" - turn Vbus on 188 | if (!Vbus_power( ON )) { 189 | send_string ("\r\nVbus overload"); 190 | } 191 | else { 192 | send_string("\r\nVbus is on\r\n"); 193 | } 194 | send_string(cli_set_menu_help); 195 | break; 196 | case( 0x33 ): //"3" - turn Vbus off 197 | Vbus_power( OFF ); 198 | send_string("\r\nVbus is off\r\n"); 199 | send_string(cli_set_menu_help); 200 | break; 201 | case( 0x34 ): //set HID boot protocol 202 | rcode = XferSetProto( 1, 0, hid_device.interface, BOOT_PROTOCOL ); 203 | if( rcode ) { //error handling 204 | send_string("\r\nError setting boot protocol. Rcode "); 205 | send_hexbyte( rcode ); 206 | } 207 | else { 208 | send_string("\r\nBoot protocol set."); 209 | } 210 | send_string(cli_prompt_set); 211 | break; 212 | case( 0x35 ): //set HID report protocol 213 | rcode = XferSetProto( 1, 0, hid_device.interface, RPT_PROTOCOL ); 214 | if( rcode ) { //error handling 215 | send_string("\r\nError setting report protocol. Rcode "); 216 | send_hexbyte( rcode ); 217 | } 218 | else { 219 | send_string("\r\nReport protocol set."); 220 | } 221 | send_string(cli_prompt_set); 222 | break; 223 | case( 0x3f ): //Question mark 224 | send_string(cli_set_menu_help); 225 | send_string(esc_prev_lvl); 226 | send_string(cli_prompt_set); 227 | break; 228 | default: 229 | send_string(cli_invalid_key); 230 | send_string(cli_prompt_set); 231 | break; 232 | } //end switch( temp ) 233 | } 234 | /* usb queries menu */ 235 | void CLI_usbq_menu( void ) 236 | { 237 | BYTE temp; 238 | if(!CharInQueue()) { 239 | return; 240 | } 241 | temp = recvchar(); 242 | if ( temp > 0x1f ) { 243 | sendchar( temp ); //echo back 244 | } 245 | switch( temp ) { 246 | case( 0x0d ): //"Enter" 247 | send_string(cli_prompt_usbq); 248 | break; 249 | case( 0x1b ): //"ESC" 250 | cli_state = CLI_MAIN_MENU; //change state to "Main" 251 | send_string(cli_prompt_main); 252 | break; 253 | case( 0x31 ): //"1" - print device descriptor 254 | printDevDescr( 1 ); 255 | send_string(cli_prompt_usbq); 256 | break; 257 | case( 0x32 ): 258 | printConfDescr( 1, 0 ); //"2" - print configuration 259 | send_string(cli_prompt_usbq); 260 | break; 261 | case( 0x33 ): //"3" - 262 | break; 263 | case( 0x3f ): //Question mark 264 | send_string(cli_usbq_menu_help); 265 | send_string(esc_prev_lvl); 266 | send_string(cli_prompt_usbq); 267 | break; 268 | default: 269 | send_string(cli_invalid_key); 270 | send_string(cli_prompt_usbq); 271 | break; 272 | } //end switch( temp ) 273 | } 274 | void CLI_usbt_menu( void ) 275 | { 276 | BYTE temp; 277 | if(!CharInQueue()) { 278 | return; 279 | } 280 | temp = recvchar(); 281 | if ( temp > 0x1f ) { 282 | sendchar( temp ); //echo back 283 | } 284 | switch( temp ) { 285 | case( 0x0d ): //"Enter" 286 | send_string(cli_prompt_usbt); 287 | break; 288 | case( 0x1b ): //"ESC" 289 | cli_state = CLI_MAIN_MENU; //change state to "Main" 290 | send_string(cli_prompt_main); 291 | break; 292 | case( 0x31 ): //"1" - test mouse 293 | testMouse( 1 ); 294 | break; 295 | case( 0x32 ): //"2" - test keyboard 296 | testKbd( 1 ); 297 | break; 298 | case( 0x33 ): //"3" - 299 | break; 300 | case( 0x3f ): //Question mark 301 | send_string(cli_usbt_menu_help); 302 | send_string(esc_prev_lvl); 303 | send_string(cli_prompt_usbt); 304 | break; 305 | default: 306 | send_string(cli_invalid_key); 307 | send_string(cli_prompt_usbt); 308 | break; 309 | } //end switch( temp ) 310 | } 311 | /* util level CLI */ 312 | /* state CLI_UTIL_MENU */ 313 | void CLI_util_menu( void ) 314 | { 315 | BYTE temp; 316 | 317 | if(!CharInQueue()) 318 | return; 319 | 320 | temp = recvchar(); 321 | 322 | if ( temp > 0x1f ) 323 | sendchar( temp ); //echo back 324 | 325 | send_string( cli_prompt_util); 326 | switch( temp ) { 327 | case( 0x0d ): //"Enter" 328 | //send_string(cli_prompt_util); 329 | break; 330 | case( 0x1b ): //"ESC" 331 | cli_state = CLI_MAIN_MENU; //change state to "Main" 332 | send_string(cli_prompt_main); 333 | break; 334 | case( 0x31 ): //"1 - test SPI" 335 | SPI_test(); 336 | send_string( cli_prompt_util ); 337 | break; 338 | case( 0x32 ): 339 | //print_registers(); //"2 - show registers" 340 | //send_string(cli_prompt_show); 341 | break; 342 | case( 0x3f ): //Question mark 343 | send_string(cli_util_menu_help); 344 | send_string(esc_prev_lvl); 345 | send_string(cli_prompt_util); 346 | break; 347 | default: 348 | send_string(cli_invalid_key); 349 | send_string(cli_prompt_util); 350 | break; 351 | } //end switch( temp ) 352 | } 353 | 354 | void CLI_init( void ) 355 | { 356 | send_string(cli_banner); 357 | send_string(cli_root_menu_help); 358 | send_string(cli_prompt_main); 359 | } 360 | /* prints device descriptor */ 361 | void printDevDescr( BYTE addr ) 362 | { 363 | BYTE rcode; 364 | USB_DEVICE_DESCRIPTOR buf; 365 | send_string( crlf ); 366 | rcode = XferGetDevDescr( addr, 0, DEV_DESCR_LEN, ( char *)&buf ); //get device descriptor 367 | if( rcode ) { 368 | send_string("\r\nDevice descriptor request error. Return code: "); 369 | send_hexbyte( rcode ); 370 | send_string( crlf ); 371 | return; 372 | } 373 | /* First line */ 374 | send_string("Vendor ID: "); 375 | send_hexbyte( HIBYTE( buf.idVendor )); 376 | send_hexbyte( LOBYTE( buf.idVendor )); 377 | send_string(" Product ID: "); 378 | send_hexbyte( HIBYTE( buf.idProduct )); 379 | send_hexbyte( LOBYTE( buf.idProduct )); 380 | send_string(" Rev.: "); 381 | send_decword(( WORD )HIBYTE( buf.bcdDevice )); 382 | sendchar('.'); 383 | send_decword(( WORD )LOBYTE( buf.bcdDevice )); 384 | send_string(" USB version: "); 385 | send_decword(( WORD )HIBYTE( buf.bcdUSB )); 386 | sendchar('.'); 387 | send_decword(( WORD )LOBYTE( buf.bcdUSB )); 388 | /* Second line */ 389 | send_string("\r\nClass: "); 390 | send_hexbyte( buf.bDeviceClass ); 391 | send_string(" Subclass: "); 392 | send_hexbyte( buf.bDeviceSubClass ); 393 | send_string(" Protocol: "); 394 | send_hexbyte( buf.bDeviceProtocol ); 395 | /* Third line */ 396 | send_string("\r\nMax.packet size: "); 397 | send_decword(( WORD )buf.bMaxPacketSize0 ); 398 | send_string(" bytes. Number of configurations: "); 399 | send_decword(( WORD )buf.bNumConfigurations ); 400 | } 401 | /* Configuraton descriptor parser/printer */ 402 | /* Makes sure configuration is less than 256 bytes which may not be the case */ 403 | /* for very complex devices */ 404 | void printConfDescr( BYTE addr, BYTE conf ) 405 | { 406 | WORD totallength; 407 | BYTE rcode; 408 | USB_DESCR *data_ptr = ( USB_DESCR * )bigbuf; //pointer to any descriptor 409 | char *byte_ptr = bigbuf; 410 | rcode = XferGetConfDescr( addr, 0, CONF_DESCR_LEN, conf, bigbuf ); //get configuration descriptor 411 | if( rcode ) { 412 | send_string("\r\nConfiguration descriptor request error 01. Return code: "); 413 | send_hexbyte( rcode ); 414 | send_string( crlf ); 415 | return; 416 | } 417 | //data_ptr = ( USB_DESCR * )bigbuf; 418 | totallength = data_ptr->descr.config.wTotalLength; //get total length of configuration 419 | if( totallength > 256 ) { 420 | send_string("\r\nConfiguration descriptor data length error. Total length: "); 421 | send_decword( totallength ); 422 | send_string( crlf ); 423 | return; 424 | } 425 | rcode = XferGetConfDescr( addr, 0, totallength, conf, bigbuf ); //get the whole configuration 426 | if( rcode ) { 427 | send_string("\r\nConfiguration descriptor request error 02. Return code: "); 428 | send_hexbyte( rcode ); 429 | send_string( crlf ); 430 | return; 431 | } 432 | /* Print configuration descriptor */ 433 | send_string("\r\nConfiguration descriptor\r\n"); 434 | /* First line */ 435 | send_string("\r\nTotal configuration size: "); 436 | send_decword( totallength ); 437 | send_string(" bytes. Max.power: "); 438 | send_decword( 2 * data_ptr->descr.config.bMaxPower ); //max.value of this field is 250 439 | send_string(" ma. Number of interfaces: "); 440 | send_decword( data_ptr->descr.config.bNumInterfaces ); 441 | /* Second line */ 442 | send_string("\r\nAttributes: "); 443 | if( data_ptr->descr.config.bmAttributes & USB_CFG_DSC_SELF_PWR ) { 444 | send_string("Self-powered "); 445 | } 446 | if( data_ptr->descr.config.bmAttributes & USB_CFG_DSC_REM_WAKE ) { 447 | send_string("Remote wakeup "); 448 | } 449 | send_string(". Configuration value: "); 450 | send_decword( data_ptr->descr.config.bConfigurationValue ); 451 | send_string( crlf ); 452 | /* Finish printing configuration descriptor. Parse the rest */ 453 | byte_ptr = byte_ptr + CONF_DESCR_LEN; 454 | while( byte_ptr < ( bigbuf + totallength )) { 455 | data_ptr = ( USB_DESCR * )byte_ptr; 456 | switch( data_ptr->descr.config.bDescriptorType ) { 457 | case( USB_DESCRIPTOR_INTERFACE ): 458 | printIntrDescr( byte_ptr ); 459 | byte_ptr = byte_ptr + INTR_DESCR_LEN; 460 | break; 461 | case( USB_DESCRIPTOR_ENDPOINT ): 462 | printEpDescr( byte_ptr ); 463 | byte_ptr = byte_ptr + EP_DESCR_LEN; 464 | break; 465 | case( HID_DESCRIPTOR_HID ): //HID descriptor is variable length 466 | printHIDdescr( byte_ptr ); 467 | byte_ptr = byte_ptr + data_ptr->descr.config.bLength; 468 | break; 469 | default: //unknown descriptor 470 | send_string("Unknown descriptor: "); 471 | send_hexbyte( data_ptr->descr.config.bDescriptorType ); 472 | send_string( crlf ); 473 | byte_ptr = byte_ptr + data_ptr->descr.config.bLength; 474 | break; 475 | }//switch( data_ptr->swcr.config.bDescriptorType 476 | } 477 | } 478 | /* prints interface descriptor */ 479 | void printIntrDescr( char *byteptr ) 480 | { 481 | USB_DESCR* dataptr = ( USB_DESCR* )byteptr; 482 | send_string("\r\nInterface Descriptor\r\n"); 483 | /* First line */ 484 | send_string("Interface number: "); 485 | send_decword( dataptr->descr.interface.bInterfaceNumber ); 486 | send_string(" Alternate setting: "); 487 | send_decword( dataptr->descr.interface.bAlternateSetting ); 488 | send_string(" Number of endpoints: "); 489 | send_decword( dataptr->descr.interface.bNumEndpoints ); 490 | /* Second line */ 491 | send_string("\r\nClass: "); 492 | send_hexbyte( dataptr->descr.interface.bInterfaceClass ); 493 | send_string(" Subclass: "); 494 | send_hexbyte( dataptr->descr.interface.bInterfaceSubClass ); 495 | send_string(" Protocol: "); 496 | send_hexbyte( dataptr->descr.interface.bInterfaceProtocol ); 497 | send_string( crlf ); 498 | } 499 | /* prints endpoint descriptor */ 500 | void printEpDescr( char* byteptr ) 501 | { 502 | USB_DESCR* dataptr = ( USB_DESCR* )byteptr; 503 | send_string("\r\nEndpoint Descriptor\r\n"); 504 | /* First line */ 505 | send_string("Endpoint number: "); 506 | send_hexbyte( dataptr->descr.endpoint.bEndpointAddress & 0x0f ); 507 | send_string(" Direction: "); 508 | if( dataptr->descr.endpoint.bEndpointAddress & 0x80 ) { 509 | send_string("IN"); 510 | } 511 | else { 512 | send_string("OUT"); 513 | } 514 | /* Second line */ 515 | send_string("\r\nAttributes: "); 516 | send_hexbyte( dataptr->descr.endpoint.bmAttributes ); 517 | send_string(" Max.packet size: "); 518 | send_decword( dataptr->descr.endpoint.wMaxPacketSize ); 519 | send_string(" Polling interval: "); 520 | send_decword( dataptr->descr.endpoint.bInterval ); 521 | send_string( crlf ); 522 | } 523 | /* prints HID descriptor. Won't parse past first( i.e. report ) descriptor fields, */ 524 | /* but will show correct length and descriptor number */ 525 | void printHIDdescr( char* byteptr ) 526 | { 527 | USB_DESCR* dataptr = ( USB_DESCR* )byteptr; 528 | send_string("\r\nHID Descriptor\r\n"); 529 | /* First line */ 530 | send_string("Descriptor length: "); 531 | send_decword( dataptr->descr.HID.bLength ); 532 | send_string(" bytes. HID version: "); 533 | send_decword(( WORD )HIBYTE( dataptr->descr.HID.bcdHID )); 534 | sendchar('.'); 535 | send_decword(( WORD )LOBYTE( dataptr->descr.HID.bcdHID )); 536 | send_string(" Country code: "); 537 | send_hexbyte( dataptr->descr.HID.bCountryCode ); 538 | /* Second line */ 539 | send_string("\r\nNumber of descriptors: "); 540 | send_decword( dataptr->descr.HID.bNumDescriptors ); 541 | /* Third line */ 542 | send_string("\r\nDescriptor type: "); 543 | send_hexbyte( dataptr->descr.HID.bDescrType ); 544 | send_string(" Descriptor length: "); 545 | send_decword( dataptr->descr.HID.wDescriptorLength ); 546 | if( dataptr->descr.HID.bLength > 9 ) { 547 | send_string("Skipping the rest of the descriptor...\r\n"); 548 | } 549 | send_string( crlf ); 550 | } 551 | /* test mouse communication */ 552 | /* coordinates report work */ 553 | /* Issue: in boot protocol mode buttons are not reported. Button press, however, generates an update. I can't find boot protocol description for mouse, */ 554 | /* so maybe it's the way it should be */ 555 | void testMouse ( BYTE addr ) 556 | { 557 | //DWORD delay; 558 | BYTE rcode; 559 | char tmpbyte; 560 | BOOT_MOUSE_REPORT buf; 561 | 562 | rcode = XferGetIdle( addr, 0, hid_device.interface, 0, &tmpbyte ); 563 | if( rcode ) { //error handling 564 | send_string("\r\nGetIdle Error. Error code "); 565 | send_hexbyte( rcode ); 566 | } 567 | else { 568 | send_string("\r\nUpdate rate: "); 569 | send_decword( tmpbyte ); 570 | } 571 | send_string("\r\nProtocol: "); 572 | rcode = XferGetProto( addr, 0, hid_device.interface, &tmpbyte ); 573 | if( rcode ) { //error handling 574 | send_string("\r\nGetProto Error. Error code "); 575 | send_hexbyte( rcode ); 576 | } 577 | else { 578 | send_decword( tmpbyte ); 579 | send_string( crlf ); 580 | } 581 | /* Polling interrupt endpoint */ 582 | while( !CharInQueue() ) { 583 | //delay = uptime + 5; 584 | //while( uptime < delay ); //wait polling interval 585 | rcode = mousePoll( &buf ); 586 | if( rcode == hrNAK ) { //NAK means no new data 587 | continue; 588 | } 589 | if( rcode ) { 590 | send_string("\r\nRcode: "); 591 | send_hexbyte( rcode ); 592 | } 593 | send_string("\r\nX displacement: "); 594 | send_decword( buf.Xdispl ); 595 | send_string(" Y displacement: "); 596 | send_decword( buf.Ydispl ); 597 | send_string(" Buttons: "); 598 | send_hexbyte( buf.button ); 599 | } 600 | } 601 | /* keyboard communication demo */ 602 | /* only basic functions/keys are supported */ 603 | void testKbd( BYTE addr ) 604 | { 605 | char i; 606 | BYTE rcode; 607 | char tmpbyte; 608 | char* byteptr; 609 | BOOT_KBD_REPORT kbdbuf; 610 | BOOT_KBD_REPORT localbuf; 611 | 612 | rcode = XferGetIdle( addr, 0, hid_device.interface, 0, &tmpbyte ); 613 | if( rcode ) { //error handling 614 | send_string("\r\nGetIdle Error. Error code "); 615 | send_hexbyte( rcode ); 616 | } 617 | else { 618 | send_string("\r\nUpdate rate: "); 619 | send_decword( tmpbyte ); 620 | } 621 | send_string("\r\nProtocol: "); 622 | rcode = XferGetProto( addr, 0, hid_device.interface, &tmpbyte ); 623 | if( rcode ) { //error handling 624 | send_string("\r\nGetProto Error. Error code "); 625 | send_hexbyte( rcode ); 626 | } 627 | else { 628 | send_decword( tmpbyte ); 629 | send_string( crlf ); 630 | } 631 | send_string("\r\nType something on PIC keyboard. Press any key on PC keyboard to stop.\r\n"); 632 | /* Polling interrupt endpoint */ 633 | while( !CharInQueue() ) { 634 | //delay = uptime + 5; 635 | //while( uptime < delay ); //wait polling interval 636 | rcode = kbdPoll( &kbdbuf ); 637 | if( rcode == hrNAK ) { //NAK means no new data 638 | continue; 639 | } 640 | // byteptr = ( char *)&kbdbuf; 641 | // send_string( crlf ); 642 | // for( i = 0; i < 8; i++ ) { 643 | // send_hexbyte( *byteptr ); 644 | // byteptr++; 645 | // } 646 | //send_string( crlf ); 647 | for( i = 0; i < 6; i++ ) { 648 | if( kbdbuf.keycode[ i ] == 0 ) { //empty position means it and all subsequent positions are empty 649 | break; 650 | } 651 | if( prevCodeComp( kbdbuf.keycode[ i ], &localbuf ) == FALSE ) { 652 | // send_hexbyte( kbdbuf.keycode[ i ] ); 653 | sendchar( HIDtoa( &kbdbuf, i )); 654 | // send_string( crlf ); 655 | } 656 | } 657 | memcpy(( far char* )&localbuf, ( const far char* )&kbdbuf, sizeof( BOOT_KBD_REPORT )); 658 | }//while(CharInQueue()... 659 | } 660 | /* function compares a key code with keycodes from previous report */ 661 | /* returns TRUE if match is found */ 662 | BOOL prevCodeComp( BYTE data, BOOT_KBD_REPORT* buf ) 663 | { 664 | BYTE i; 665 | for( i = 0; i < 6; i++ ) { 666 | if( buf->keycode[ i ] == data ) { 667 | return( TRUE ); 668 | } 669 | } 670 | return( FALSE ); 671 | } 672 | /* function to convert HID keyboard code to ASCII */ 673 | BYTE HIDtoa( BOOT_KBD_REPORT* buf, BYTE index ) 674 | { 675 | BYTE HIDcode = buf->keycode[ index ]; 676 | //BYTE AsciiVal; 677 | //BYTE ShiftkeyStatus = 0; 678 | /* symbols a-z,A-Z */ 679 | if( HIDcode >= 0x04 && HIDcode <= 0x1d ) { 680 | if( buf->mod.LShift || buf->mod.RShift ) { //uppercase 681 | return( HIDcode + 0x3d ); 682 | } 683 | if( buf->mod.LCtrl || buf->mod.RCtrl ) { //Ctrl 684 | return( HIDcode - 3 ); 685 | } 686 | return( HIDcode + 0x5d ); //lowercase 687 | } 688 | /* Numbers 1-9,0 */ 689 | if( HIDcode >= 0x1e && HIDcode <= 0x27 ) { 690 | if( buf->mod.LShift || buf->mod.RShift ) { //uppercase 691 | switch( HIDcode ) { 692 | case( 0x1f ): //HID code for '2' 693 | return('@'); 694 | case( 0x23 ): //HID code for '6' 695 | return('^'); 696 | case( 0x24 ): //HID code for '7' 697 | return('&'); 698 | case( 0x25 ): //HID code for '8' 699 | return('*'); 700 | case( 0x26 ): //HID code for '9' 701 | return('('); 702 | case( 0x27 ): //HID code for '0' 703 | return(')'); 704 | default: //1,3,4,5 705 | return( HIDcode + 3 ); 706 | } 707 | } 708 | return( HIDcode + 0x13 ); 709 | } 710 | /* Misc. non-modifiable keys in no particular order */ 711 | switch( HIDcode ) { 712 | case( 0x28 ): //Enter 713 | return( 0x0d ); //CR 714 | case( 0x29 ): //ESC 715 | return( 0x1b ); //ESC 716 | case( 0x2c ): //spacebar 717 | return( 0x20 ); // 718 | case( 0x36 ): //comma 719 | return(','); 720 | case( 0x37 ): //dot 721 | return('.'); 722 | } 723 | return( 0x07 ); //Bell 724 | } 725 | 726 | /* tests SPI transfers for errors. Cycles indefinitely until a key is pressed. */ 727 | /* Prints "." every 64K of transferred data */ 728 | void SPI_test( void ) 729 | { 730 | BYTE i, j, gpinpol_copy; 731 | gpinpol_copy = MAXreg_rd( rGPINPOL ); //save GPINPOL 732 | send_string("Testing SPI transfers. Press any key to stop.\r\n"); 733 | while( !CharInQueue()) { //loop until any key is pressed 734 | for( i = 0; i < 255; i++ ) { 735 | MAXreg_wr( rGPINPOL, i ); 736 | if( MAXreg_rd( rGPINPOL ) != i ) { 737 | send_string("SPI transmit/receive mismatch\r\n"); 738 | return; 739 | } 740 | } 741 | j++; 742 | if ( j == 0 ) 743 | send_string("."); 744 | } 745 | i = recvchar(); 746 | MAXreg_wr( rGPINPOL, gpinpol_copy ); 747 | } 748 | 749 | //end cli.c 750 | --------------------------------------------------------------------------------