/* Zajimave materialy - http://blogs.msdn.com/b/usbcoreblog/archive/2009/10/31/how-does-usb-stack-enumerate-a-device.aspx#_Second_Device_Descriptor - www.usb.org/developers/docs/USB_LANGIDs.pdf */ #ifndef __dvoraj42cpp__ #define __dvoraj42cpp__ /******************************************************************************/ //includes #include #include "func_dvoraj42.h" /******************************************************************************/ //Circular data send buffer u8 uart_send_buffer[UART_BUFFER_SIZE]; //memory unsigned int uart_sb_read=0, uart_sb_write=0; //write and read indexes u8 outputDataBuffer[256]; u8 inputDataBuffer[256]; /******************************************************************************/ //Pointer (void *) to USB_PMA void *uUSB_PMA = (void*) ( (vu8*)(USB_PMA) ); //pointer to USB_PMA address /******************************************************************************/ //Struct with EndPoint addresses and sizes //End Point 0 addresses + sizes EP_address EP0 = {0x80, 0x00, 0x10, 0x8400}; //128, 0; 16, 64 //End Point 1 addresse, ... EP_address EP1 = {0x40, 0x00, 0x0, 0x8400}; /******************************************************************************/ //Device descriptor //string desc. ids descriptor_device device_descriptor = {18, 0x01, 0x0110, 0 , 0, 0, 64, 0xFFA0, 0x02FA, 0x0001, 0x01, 0x02, 0x03, 1}; //FFA0 + 02FA vymysl - je opravdu neznamy //046D = Logitech; C00B = mouse man+wheel; 0x0001 = BCD version //Configuration descriptor //18 casem 25 az se bude posilat i EP desc descriptor_configuration configuration_descriptor = {9, 0x02, 25, 0x01, 0x01, 0x04, 0xC0, 0x32}; //Interface descriptor //0 -> casem 1 - #EP descriptor_interface interface_descriptor = {9, 0x4, 0x0, 0x0, 1, 0x0, 0x0, 0x0, 0x5}; //End point descriptor //buffer size descriptor_endpoint endpoint_descriptor = {7, 0x5, 0x01 , 0x2, 8, 0x0}; // //String descriptor // 1 = manufacturer; 2 = Product; 3 = serial;; 4 = descriptor config;; 5 = descriptor interf;; descriptor_string string_descriptor = {4, 0x3, 0x0405}; //0x0405 = Czech //www.usb.org/developers/docs/USB_LANGIDs.pdf descriptor_stringInfo sdi_manufacturer = {22, 0x3, 'J', 0, 'a', 0, 'n', 0, ' ', 0, 'D', 0, 'v', 0, 'o', 0, 'r', 0, 'a', 0, 'k', 0 }; descriptor_stringInfo sdi_product = {26, 0x3, 'd', 0, 'v', 0, 'o', 0, 'r', 0, 'a', 0, 'j', 0, '4', 0, '2', 0, ' ', 0, 'U', 0, 'S', 0, 'B', 0 }; descriptor_stringInfo sdi_serial = {10, 0x3, '0', 0, '0', 0, '1', 0, '0', 0 }; // descriptor_stringInfo sdi_config = {22, 0x3, 'J', 0, 'a', 0, 'n', 0, ' ', 0, 'D', 0, 'v', 0, 'o', 0, 'r', 0, 'a', 0, 'k', 0 }; // descriptor_stringInfo sdi_interface = {22, 0x3, 'J', 0, 'a', 0, 'n', 0, ' ', 0, 'D', 0, 'v', 0, 'o', 0, 'r', 0, 'a', 0, 'k', 0 }; /******************************************************************************/ //Led period u8 ledPeriod = 8; //actual blink speed u8 ledCounter = 0; /******************************************************************************/ /** * Swap bytes * @param(int) number * @returns(int) swapped number */ int swapBytes(int number) { int up = number >> 0x8 ; int dw = number & ( ( (1<<8)-1 ) ); return (dw << 0x8 )+ up; } /******************************************************************************/ /** * Copy data to outputDataBuffer * @param {void *} data * @param {int} length */ void copyDataToOutputBuffer(void* data, int length) { appendDataToOutputBuffer(data, 0, length); } /******************************************************************************/ /** * Copy data to outputDataBuffer * @param {void *} data * @param {int} start * @param {int} length */ void appendDataToOutputBuffer(void* data, int start, int length) { int i; u8 *dt; dt = (u8*) data; for( i=0; iUSB_count_tx = length; //set data length //get transmit address vu32 address = (ep->USB_addr_tx); //16b VS 32b u16 data; int writeOffset = 0; //copy output data buffer into memory int i; for( i=0; iEP0R = EPnR; //Wait until PC reads it - 7th bit p. 293 while ((USB->EP0R & 0x0080) != 0x0080) { atteps++; if( atteps>=MAX_LOOP ) { UARTSendMessage( (u8*) "MAX LOOP EXCEPTION\r\n" ); break; //not to freeze the CPU } } break; //EP 1 case 1: USB->EP1R = EPnR | 0x01; //last 4 bits are address of EP break; } } /******************************************************************************/ /** * Read data from buffer * @param {int} endPoint * @param {int} length */ void readInputDataIntoBuffer(int endPoint, int length) { //get end point structure EP_address* ep = ( (EP_address *) (uUSB_PMA ) ) + endPoint; //USB_PMA + ep*sizeOf(EP_address) //get recieve address vu32 address = (ep->USB_addr_rx) * 2; //16b VS 32b //get all data int i; int readOffset = 0; for( i=0; iUART_BUFFER_SIZE )return; //too long //if( (uart_sb_read-uart_sb_write-1)=UART_BUFFER_SIZE )uart_sb_write-=UART_BUFFER_SIZE; } //ENABLE UART_ItConfig(UART2, UART_TxEmpty, ENABLE); } void UARTSendHexaNumber(u16 number) { u8 l = (u8) (number & 0xF); //get lower byte u8 h = (u8) ( (number >> 0x4) & 0xF ); //get upper byte UARTSendHexaLetter(h); UARTSendHexaLetter(l); } void UARTSendHexaLetter(u8 letter) { u8 let[2]; if( letter<10 ) let[0] = (48 + letter); //0 - 9 asc(O) = 48 else let[0] = (55+letter); //A - F asc(A) = 65 let[1]='\0'; UARTSendMessage(let); } void UARTSendBuffer(u8* start, int length) { int i=0; while( i < length ) //interate until zero char { UARTSendHexaNumber( start[i] ); UARTSendMessage( (u8*) " " ); //insert gab i++; } } /******************************************************************************/ /** * Initialize peripheries - enable clock */ void initPeripheries() { APB_ClockConfig(APB2, ENABLE, GPIO2_Periph); APB_ClockConfig(APB2, ENABLE, TIM0_Periph); APB_ClockConfig(APB1, ENABLE, UART2_Periph); APB_ClockConfig(APB1, ENABLE, USB_Periph); } /******************************************************************************/ /** * Initialize clock speed; set up multipling parts */ void initClockTiming() { RCCU_Div2Config(DISABLE); RCCU_MCLKConfig(RCCU_DEFAULT); /* MCLK = CK * 12 */ RCCU_PCLK1Config(RCCU_RCLK_2); /* PCLK = CK * 12 / 2 */ RCCU_PCLK2Config(RCCU_RCLK_2); RCCU_RCLKSourceConfig(RCCU_CLOCK2); //Wait until multiply 12 is ready RCCU_PLL1Config(RCCU_PLL1_Mul_12, RCCU_Div_1); while (RCCU_FlagStatus(RCCU_PLL1_LOCK) == RESET) ; RCCU_RCLKSourceConfig(RCCU_PLL1_Output); //Wait until multiply 12 (for USB) is ready RCCU_PLL2Config(RCCU_PLL2_Mul_12, RCCU_Div_1, 4000000); //4MHz while (PCU->PLL2CR & 0x8000 == 0) ; //check 15th bit RCCU_USBCLKConfig(RCCU_PLL2_Output); //USB now at 48K } /******************************************************************************/ /** * Initialize uart */ void initUART() { //UART - port 0, pin 14, alternative push pull GPIO_Config (GPIO0, 0x4000, GPIO_AF_PP ); UART_Init (UART2); UART_Config (UART2, 115200, UART_NO_PARITY, UART_1_StopBits, UARTM_8D); UART_ItConfig(UART2, UART_TxFull, ENABLE); UART_OnOffConfig (UART2, ENABLE); } /******************************************************************************/ /** * Initialize interrupts */ void initInterrupts() { //TIMER settings TIM_Init(TIM0); TIM_ClockSourceConfig(TIM0, TIM_INTERNAL); TIM_PrescalerConfig(TIM0, 100); TIM_ITConfig(TIM0, TIM_TO_IT, ENABLE); TIM_CounterConfig(TIM0, TIM_START); EIC_IRQChannelPriorityConfig(T0TOI_IRQChannel, 1); EIC_IRQChannelConfig(T0TOI_IRQChannel, ENABLE); //For UART EIC_IRQChannelPriorityConfig(UART2_IRQChannel, 1); EIC_IRQChannelConfig(UART2_IRQChannel, ENABLE); //For USB EIC_IRQChannelPriorityConfig(USBLP_IRQChannel, 1); EIC_IRQChannelConfig(USBLP_IRQChannel, ENABLE); //Set USB control Register p. 283 // enable RESET (10th); ERR (13th); CTR interrupts (15th) USB->CNTR=0xA400; //0x8000 + 0x2000 + 0x400 //Clear USB interrupt Tegister p. 285 USB->ISTR=0; //Set USB Address to 0 - not enumerated p. 291 USB->DADDR=0; EIC_IRQConfig(ENABLE); } /******************************************************************************/ /** * Interrupt from UART */ void interruptUART() { if( uart_sb_read == uart_sb_write ) { UART_ItConfig(UART2, UART_TxEmpty, DISABLE);//nothing to send }else{ UART_ByteSend(UART2, &uart_send_buffer[uart_sb_read++]); //send byte if( uart_sb_read>=UART_BUFFER_SIZE )uart_sb_read-=UART_BUFFER_SIZE; } } /******************************************************************************/ /** * Interrupt from USB */ void interruptUSB() { //RESET if( (USB->ISTR & 0x400) == 0x400 ) //10th bit p. 285 { resetUSB(); } //ERROR detection if( (USB->ISTR & 0x2000) == 0x2000 ) //13th bit { errorUSB(); } //CORRECT TRANSFER if( (USB->ISTR & 0x8000) == 0x8000 ) //15th bit { correctUSB(); } } /******************************************************************************/ /** * Get recieved bytes count * @param{int} end point number * @returns{u16} recieved bytes count */ u16 getRecievedBytesCount(int endPoint) { EP_address* ep = ( (EP_address *) (uUSB_PMA ) ) + endPoint; //USB_PMA + ep*sizeOf(EP_address) return (u16) (ep->USB_count_rx & 0x3FF ); } /******************************************************************************/ /** * USB Correct transfer */ void correctUSB() { //correct transfer - 15th bit is READ ONLY - p. 286 //direction of transfer - ISTR bit 4; p. 289 int direction = ( USB->ISTR & 0x10 ) >> 4; //2^4 = 0x10; dir = 0 IN transakce(TX); dir = 1 OUT transakce(RX || TX) //get EP - ISTR bit [3:0] - 4bits int endPointNumber = ( USB->ISTR & 0xF ); //0001111 = 0xF //get count vu16 uCount = getRecievedBytesCount(endPointNumber); //reaction to the End Point number switch (endPointNumber) { case 0: //EP0 //recieved if( direction==1 ) { USB->EP0R = EPnR_RECIEVED; //Decode request readInputDataIntoBuffer(endPointNumber, uCount ); //Read input data into array UARTSendMessage( (u8 *)"RECIEVED ON EP0: " ); UARTSendBuffer( &inputDataBuffer[0], uCount ); UARTSendMessage( (u8 *)"\r\n" ); //Device descriptor request if( uCount>=4 && inputDataBuffer[0]==0x80 && inputDataBuffer[1]==0x6 && inputDataBuffer[2]==0x0 && inputDataBuffer[3]==0x1) { //Send all 18bytes if( inputDataBuffer[6]==18 ) { copyDataToOutputBuffer( (void*)(&device_descriptor) ,18); //copy to output buffer sendDataFromBuffer(endPointNumber, 18, EPnR_READY); //send output buffer UARTSendMessage( (u8 *)"SEND FULL DEV DESC: " ); UARTSendBuffer( &outputDataBuffer[0], 18); UARTSendMessage( (u8 *)"\r\n" ); //Send first 8bytes }else{ copyDataToOutputBuffer( (void*)(&device_descriptor) ,8); //copy to output buffer sendDataFromBuffer(endPointNumber, 8, EPnR_READY); //send output buffer UARTSendMessage( (u8 *)"SEND 8b OF DEV DESC: " ); UARTSendBuffer( &outputDataBuffer[0], 8 ); UARTSendMessage( (u8 *)"\r\n" ); } } //Change address else if( uCount>=2 && inputDataBuffer[0]==0x0 && inputDataBuffer[1]==0x5 ) { int na = inputDataBuffer[2]; //new address //send empty data - request accepted sendDataFromBuffer(endPointNumber, 0, EPnR_READY); //send output buffer //set new address USB->DADDR = (u16) ( na | 0x80 ); //new addres + Enable Function //info output UARTSendMessage( (u8 *)"SET ADDRESS: "); UARTSendHexaNumber(na); UARTSendMessage( (u8 *)"\r\n" ); UARTSendMessage( (u8 *)"SEND EMPTY PACKET\r\n" ); } //Configuration descriptor - 9bytes else if( uCount>=4 && inputDataBuffer[0]==0x80 && inputDataBuffer[1]==0x6 && inputDataBuffer[2]==0x0 && inputDataBuffer[3]==0x2) { //Fill buffer with conf + interf + ep copyDataToOutputBuffer( (void*)(&configuration_descriptor) ,9); appendDataToOutputBuffer( (void*)(&interface_descriptor) ,9, 9); appendDataToOutputBuffer( (void*)(&endpoint_descriptor) ,18, 7); //Configuration desc if( inputDataBuffer[6]==9 ) { sendDataFromBuffer(endPointNumber, 9, EPnR_READY); //send output buffer UARTSendMessage( (u8 *)"SEND CONF DESC: " ); UARTSendBuffer( &outputDataBuffer[0], 9 ); UARTSendMessage( (u8 *)"\r\n" ); //Configuration + interface desc // NO EP1 specification }else if( inputDataBuffer[6]==0x12 ){ //18 = 9 + 9 sendDataFromBuffer(endPointNumber, 18, EPnR_READY); //send output buffer UARTSendMessage( (u8 *)"SEND CONF + INTERF DESC: " ); UARTSendBuffer( &outputDataBuffer[0], 18 ); UARTSendMessage( (u8 *)"\r\n" ); //Configuration + interface + ep desc }else{ sendDataFromBuffer(endPointNumber, 25, EPnR_READY); //send output buffer UARTSendMessage( (u8 *)"SEND CONF + INTERF + EP1 DESC: " ); UARTSendBuffer( &outputDataBuffer[0], 25 ); UARTSendMessage( (u8 *)"\r\n" ); } } //String descriptor else if( uCount>=4 && inputDataBuffer[0]==0x80 && inputDataBuffer[1]==0x6 && inputDataBuffer[3]==0x3) { switch( inputDataBuffer[2] ) { //Send language support list case 0: copyDataToOutputBuffer( (void*)(&string_descriptor) ,4); sendDataFromBuffer(endPointNumber, 4, EPnR_READY); //send output buffer UARTSendMessage( (u8 *)"SEND STRING DESC: " ); UARTSendBuffer( &outputDataBuffer[0], 4 ); UARTSendMessage( (u8 *)"\r\n" ); break; //Send serial number string case 3: copyDataToOutputBuffer( (void*)(&sdi_serial ) ,10); sendDataFromBuffer(endPointNumber, 10, EPnR_READY); //send output buffer UARTSendMessage( (u8 *)"SEND STRING DESC - SERIAL: " ); UARTSendBuffer( &outputDataBuffer[0], 10 ); UARTSendMessage( (u8 *)"\r\n" ); break; //Send product id string case 2: copyDataToOutputBuffer( (void*)(&sdi_product) ,26); sendDataFromBuffer(endPointNumber, 26, EPnR_READY); //send output buffer UARTSendMessage( (u8 *)"SEND STRING DESC - PRODUCT: " ); UARTSendBuffer( &outputDataBuffer[0], 26 ); UARTSendMessage( (u8 *)"\r\n" ); break; //Send manufacturer string case 1: copyDataToOutputBuffer( (void*)(&sdi_manufacturer) ,22); sendDataFromBuffer(endPointNumber, 22, EPnR_READY); //send output buffer UARTSendMessage( (u8 *)"SEND STRING DESC - MANUF: " ); UARTSendBuffer( &outputDataBuffer[0], 22 ); UARTSendMessage( (u8 *)"\r\n" ); break; } } //????? => Ignored - empty response else if( uCount>=4 && inputDataBuffer[0]==0x80 && inputDataBuffer[1]==0x6 && inputDataBuffer[2]==0x0 && inputDataBuffer[3]==0x6) { sendDataFromBuffer(endPointNumber, 0, EPnR_READY); //send output buffer } //Set configuration else if( uCount>=4 && inputDataBuffer[0]==0x00 && inputDataBuffer[1]==0x09) { sendDataFromBuffer(endPointNumber, 0, EPnR_READY); //send output buffer UARTSendMessage( (u8 *)"SET CONFIGURATION: " ); UARTSendBuffer( &outputDataBuffer[0], 0 ); UARTSendMessage( (u8 *)"\r\n" ); } //Unknown else if( uCount>0 ){ UARTSendMessage( (u8 *)"UNKNOWN\r\n" ); sendDataFromBuffer(endPointNumber, 0, EPnR_READY); //send output buffer } //transmitted }else{ //PC ack of the message USB->EP0R = EPnR_TRANSMITTED; UARTSendMessage( (u8 *)"TRANSMITTED EP0\r\n" ); } break; //EP 1 case 1: //recieved if( direction==1 ) { USB->EP1R = EPnR_RECIEVED | 0x01; //EP1 last 4 bits are address = 0001 //decode request readInputDataIntoBuffer(endPointNumber, uCount ); //Read input data into array UARTSendMessage( (u8 *)"RECIEVED ON EP1: " ); UARTSendBuffer( &inputDataBuffer[0], uCount ); UARTSendMessage( (u8 *)"\r\n" ); //set led period if( inputDataBuffer[0]>='0' && inputDataBuffer[0]<='9' ) { ledPeriod = (int) ( (inputDataBuffer[0]) - '0' ); } //send empty data - request accepted sendDataFromBuffer(endPointNumber, 0, EPnR_READY); //send output buffer }else{ //PC ack of the message USB->EP1R = EPnR_TRANSMITTED; UARTSendMessage( (u8 *)"TRANSMITTED EP1\r\n" ); } break; default: UARTSendMessage( (u8 *)"UNKNOWN ENDPOINT\r\n" ); } } /******************************************************************************/ /** * USB Reset */ void resetUSB() { //reset request USB->ISTR &= ~(0x400); //clear 10th bit UARTSendMessage( (u8 *)"RESET\r\n" ); //set adress USB->DADDR = 0x80; //Enable Function + 7th bit + addr - zero now; p. 291 //B - table = 0 USB->BTABLE = 0; //place EP adresses on PMA *( (EP_address *) uUSB_PMA ) = EP0; //on PMA address *( ( (EP_address *) uUSB_PMA )+1 ) = EP1; //on PMA address + sizeof(EP_address) /* USB->EP0R = 0; p. 293 USB->EP0R |= 1800; //RX = 11 13+12 bit USB->EP0R |= 10; //TX = [1]0 5+4bit USB->EP0R &= ~(0x8);//TX = 1[0] USB->EP0R &= ~(0xF); //clear EP adress [3:0] USB->EP0R &= ~(0x100); //ep kind = 0 //8 bit //ep type = 01 */ USB->EP0R = 0x3220; //viz zakomentovany kod USB->EP1R = 0x3001; //0011 | 0000 | 0000 | 0001 : RX = 11 = valid ;; ;; ;; ep address //no TX - EP1 is one directional } /******************************************************************************/ /** * USB Error */ void errorUSB() { //error USB->ISTR &= ~(0x2000); //clear 13th bit - reset ack UARTSendMessage( (u8 *)"ERROR\r\n" ); } /******************************************************************************/ /** * USB Error */ void ledInterrupt() { //SWITCH LEDS TIM_FlagClear(TIM0, TIM_TOF); ledCounter++; if( ledCounter>= ledPeriod ) { ledCounter=0; GPIO_BitWrite(GPIO2, 15, ~GPIO_BitRead(GPIO2, 15)); GPIO_BitWrite(GPIO2, 14, ~GPIO_BitRead(GPIO2, 14)); } } /******************************************************************************/ #endif