#include #include "lpc176x.h" #include "hal.h" #include "main.h" #include "usb_hardware.h" #ifdef USBTMC // #endif в конце файла #define _ENDPOINTS_C_ #include "endpoints.h" #include "usb_application.h" #include "usb_proto.h" #include "usbtmc.h" const BYTE abDescriptors_USBTMC[] = { // ======================================================================================= // ============================ Device descriptor ======================================== // ======================================================================================= // ---------------------------------------------------------------------- // # bLength sizeof(USB_DEVICE_DESCRIPTOR), // ---------------------------------------------------------------------- // # bDescriptorType USB_DESCR_TYPE_DEVICE, // ---------------------------------------------------------------------- // # bcdUSB TWOBYTES_LE(0x0200), //-- bcdUSB 2.00 // ---------------------------------------------------------------------- // # bDeviceClass // bDeviceClass >> по USBTMC всегда 0x00 0x00, // ---------------------------------------------------------------------- // # bDeviceSubClass // bDeviceSubClass >> по USBTMC всегда 0x00 0x00, // ---------------------------------------------------------------------- // # bDeviceProtocol // bDeviceProtocol >> по USBTMC всегда 0x00 0x00, // ---------------------------------------------------------------------- // # bMaxPacketSize для EP0, для USB 2.0 всегда 64 USB_MAX_PACKET0, // ---------------------------------------------------------------------- // # idVendor - Planar TWOBYTES_LE(0x2226), // ---------------------------------------------------------------------- // # idProduct - Auto Calibration Module SCPI TWOBYTES_LE(0x000F), // ---------------------------------------------------------------------- // # bcdDevice 1.00 TWOBYTES_LE(0x0100), // ---------------------------------------------------------------------- // # iManufacturer - index of string 1 2, // ---------------------------------------------------------------------- // # iProduct - index of string 2 1, // ---------------------------------------------------------------------- // # iSerialNumber - index of string 3 4, #warning Нужен уникальный iSerialNumber, а не 00000000. USBTMC spec, see 5.1 Device Descriptor Table 40 -- Device Descriptor // --------------------------------------------------------------------- // # bNumConfigurations 1, // ======================================================================================= // ============================ Configuration descriptor ================================= // ======================================================================================= // # bLength sizeof(USB_CONFIGURATION_DESCRIPTOR), // ---------------------------------------------------------------------- // # bDescriptorType USB_DESCR_TYPE_CONFIGURATION, // ---------------------------------------------------------------------- // # wTotalLength TWOBYTES_LE( // length of configuration desc sizeof(USB_CONFIGURATION_DESCRIPTOR) + // length of interface desc sizeof(USB_INTERFACE_DESCRIPTOR) + //-- 1st Interface // length of bulk-endpoints phy4, phy5 desc, interrupt phy 3 NUM_ENDPOINTS * sizeof(USB_ENDPOINT_DESCRIPTOR) ), // ---------------------------------------------------------------------- // # bNumInterfaces 0x01, // ---------------------------------------------------------------------- // # bConfigurationValue 0x01, // ---------------------------------------------------------------------- // # iConfiguration 0x03, // ---------------------------------------------------------------------- // # bmAttributes USB_CONFIG_BUS_POWERED | USB_CONFIG_REMOTE_WAKEUP, // ---------------------------------------------------------------------- // # bMaxPower (mA /2) 100>>1, // ======================================================================================= // ============================ Interface descriptor ===================================== // ======================================================================================= // # bLength sizeof(USB_INTERFACE_DESCRIPTOR), // ---------------------------------------------------------------------- // # bDescriptorType USB_DESCR_TYPE_INTERFACE, // ---------------------------------------------------------------------- // # bInterfaceNumber 0x00, // ---------------------------------------------------------------------- // # bAlternateSetting 0x00, // ---------------------------------------------------------------------- // # bNumEndPoints NUM_ENDPOINTS, // ---------------------------------------------------------------------- // # bInterfaceClass // bInterfaceClass >> по USBTMC spec (page 33) == 0xFE 0xFE, // ---------------------------------------------------------------------- // # bInterfaceSubClass // bInterfaceSubClass >> по USBTMC spec (page 33) == 0x03 0x03, // ---------------------------------------------------------------------- // # bInterfaceProtocol // bInterfaceProtocol >> по USBTMC spec (page 33) == 0x01 0x01, // ---------------------------------------------------------------------- // # iInterface // index of string descriptor describing this interface 3, // ======================================================================================= // ================= Physical EndPoint 4 descriptor ====================================== // ======================================================================================= // # bLength sizeof(USB_ENDPOINT_DESCRIPTOR), // ---------------------------------------------------------------------- // # bDescriptorType USB_DESCR_TYPE_ENDPOINT, // ---------------------------------------------------------------------- // # bEndpointAddress, Out, EP4 0x02, // ---------------------------------------------------------------------- // # bmAttributes, Bulk 0x02, // ---------------------------------------------------------------------- // # wMaxPacketSize, 64 TWOBYTES_LE(USB_MAX_PACKET2), // ---------------------------------------------------------------------- // # bInterval, *ignored for bulk!* 0x00, // ======================================================================================= // ================= Psysical EndPoint 5 descriptor ====================================== // ======================================================================================= // # bLength sizeof(USB_ENDPOINT_DESCRIPTOR), // ---------------------------------------------------------------------- // # bDescriptorType USB_DESCR_TYPE_ENDPOINT, // ---------------------------------------------------------------------- // # bEndpointAddress, In, EP5 0x82, // ---------------------------------------------------------------------- // # bmAttributes, Bulk 0x02, // ---------------------------------------------------------------------- // # wMaxPacketSize, 64 TWOBYTES_LE(USB_MAX_PACKET2), // ---------------------------------------------------------------------- // # bInterval, *ignored for bulk!* 0x00, // ---------------------------------------------------------------------- #ifdef __SERIAL_POLL_SUPPORT__ // ======================================================================================= // ================= Psysical EndPoint 3 descriptor ====================================== // ======================================================================================= // # bLength sizeof(USB_ENDPOINT_DESCRIPTOR), // ---------------------------------------------------------------------- // # bDescriptorType USB_DESCR_TYPE_ENDPOINT, // ---------------------------------------------------------------------- // # bEndpointAddress, In, EP5 0x81, // ---------------------------------------------------------------------- // # bmAttributes, Interrupt 0x03, // ---------------------------------------------------------------------- // # wMaxPacketSize, 64 TWOBYTES_LE(USB_MAX_PACKET1), // ---------------------------------------------------------------------- // # bInterval, VALUE = 2 ^ (bInterval-1); 1<=VALUE<=16, see USB 2.0 Spec, Table 9-13. Standard Endpoint Descriptor (Continued) 0x08, // ---------------------------------------------------------------------- #endif // ======================================================================================= // ================== String descriptors ================================================= // ======================================================================================= // ##### 0 String Descriptior describes support languages ( USB-IF Spec ) // # bLength 4, // ---------------------------------------------------------------------- // # bDescriptorType USB_DESCR_TYPE_STRING, // ---------------------------------------------------------------------- // # Lang - English TWOBYTES_LE(0x0409), // ---------------------------------------------------------------------- #if defined(PLANAR) // ##### 1 String Descriptior describes device name // # bLength 38, // ---------------------------------------------------------------------- // # DescriptorType USB_DESCR_TYPE_STRING, // ---------------------------------------------------------------------- // Text in unicode 'A', 0, 'u', 0, 't', 0, 'o', 0, 'C', 0, 'a', 0, 'l', 0, ' ', 0, 'M', 0, 'o', 0, 'd', 0, 'u', 0, 'l', 0, 'e', 0, ' ', 0, 'A', 0, 'C', 0, 'M', 0, // ---------------------------------------------------------------------- #elif defined(CMT) // ##### 1 String Descriptior describes device name // # bLength 38, // ---------------------------------------------------------------------- // # DescriptorType USB_DESCR_TYPE_STRING, // ---------------------------------------------------------------------- // Text in unicode 'A', 0, 'u', 0, 't', 0, 'o', 0, 'C', 0, 'a', 0, 'l', 0, ' ', 0, 'M', 0, 'o', 0, 'd', 0, 'u', 0, 'l', 0, 'e', 0, ' ', 0, 'A', 0, 'C', 0, 'M', 0, // ---------------------------------------------------------------------- #else #error Please, specify VENDOR macro #endif #if defined(PLANAR) 68, //-- bLength USB_DESCR_TYPE_STRING, //-- bDescriptorType 'P', 0, 'l', 0, 'a', 0, 'n', 0, 'a', 0, 'r', 0, ' ', 0, '(', 0, 'h', 0, 't', 0, 't', 0, 'p', 0, ':', 0, '/', 0, '/', 0, 'w', 0, 'w', 0, 'w', 0, '.', 0, 'p', 0, 'l', 0, 'a', 0, 'n', 0, 'a', 0, 'r', 0, 'c', 0, 'h', 0, 'e', 0, 'l', 0, '.', 0, 'r', 0, 'u', 0, ')', 0, #elif defined(CMT) // ##### 2 String Descriptior describes manufacturer name // # bLength 122, // ---------------------------------------------------------------------- // # DescriptorType USB_DESCR_TYPE_STRING, //-- bDescriptorType // ---------------------------------------------------------------------- 'C', 0, 'o', 0, 'p', 0, 'p', 0, 'e', 0, 'r', 0, ' ', 0, 'M', 0, 'o', 0, 'u', 0, 'n', 0, 't', 0, 'a', 0, 'i', 0, 'n', 0, ' ', 0,//16 'T', 0, 'e', 0, 'c', 0, 'h', 0, 'n', 0, 'o', 0, 'l', 0, 'o', 0, 'g', 0, 'i', 0, 'e', 0, 's', 0, ' ', 0, '(', 0, 'h', 0, 't', 0, //32 't', 0, 'p', 0, ':', 0, '/', 0, '/', 0, 'c', 0, 'o', 0, 'p', 0, 'p', 0, 'e', 0, 'r', 0, 'm', 0, 'o', 0, 'u', 0, 'n', 0, 't', 0, 'a', 0, 'i', 0, 'n', 0, 't', 0, 'e', 0, 'c', 0, 'h', 0, '.', 0, 'c', 0, 'o', 0, 'm', 0, ')', 0, //60 // ---------------------------------------------------------------------- #else #error Please, specify VENDOR macro #endif // ##### 3 String Descriptior describes interface name // # bLength 28, // ---------------------------------------------------------------------- // # DescriptorType USB_DESCR_TYPE_STRING, //-- bDescriptorType // ---------------------------------------------------------------------- 'U', 0, 'S', 0, 'B', 0, 'T', 0, 'M', 0, 'C', 0, '-', 0, 'U', 0, 'S', 0, 'B', 0, '4', 0, '8', 0, '8', 0, // ##### 4 String Descriptior describes interface serial number, USB_SN_STRING_DESCRIPTOR // # bLength // ---------------------------------------------------------------------- //-- Terminating zero 0 }; // ---------------------------------------------------------------------- BYTE SerialNumberDescriptor[] = { 18, // ---------------------------------------------------------------------- // # DescriptorType USB_DESCR_TYPE_STRING, //-- bDescriptorType // ---------------------------------------------------------------------- '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, }; void ModifySerialNumberDescriptor( const char * sn, unsigned int maxsize ) { uint8_t * pSerial = SerialNumberDescriptor; int32_t limit = sizeof(SerialNumberDescriptor) - 2; pSerial++; // skip length in @SerialNumberDescriptor pSerial++; // skip type in @SerialNumberDescriptor for( unsigned int i = 0; (limit > 0) && (maxsize > 0); ++i ) { *pSerial = *sn; // copy pSerial++; // skip current character (low) pSerial++; // skip current character (high) limit-=2; maxsize--; // sn++; // } } // ==================================================================================================================== static inline void USB_INTERRUPT_CLEAR_BULKIN() { #ifdef MYDEBUG_OLDMETHOD rUSBEpIntClr = 1<<(USB_EP_PHY_ADDRESS_BULK_IN); #else USB_EpIntrClr( USB_EP_PHY_ADDRESS_BULK_IN ); #endif } static inline void USB_INTERRUPT_CLEAR_BULKOUT() { #ifdef MYDEBUG_OLDMETHOD rUSBEpIntClr = 1<<(USB_EP_PHY_ADDRESS_BULK_OUT); #else USB_EpIntrClr( USB_EP_PHY_ADDRESS_BULK_OUT ); #endif } static inline void USB_INTERRUPT_CLEAR_INTIN() { #ifdef MYDEBUG_OLDMETHOD rUSBEpIntClr = 1<<(USB_EP_PHY_ADDRESS_INT_IN); #else USB_EpIntrClr( USB_EP_PHY_ADDRESS_INT_IN ); #endif } // ==================================================================================================================== // ==================================================================================================================== // ==================================================================================================================== #ifdef __SERIAL_POLL_SUPPORT__ // Реализация Serial Poll для USB488 // // Точка InterruptIN Отдает два байта структуры _INTERRUPT_IN, описаной в USB488, стр 9 // void usb_EP1_tx_int_func(USB_DEVICE_INFO * udi) //-- Interrupt IN { USB_INTERRUPT_CLEAR_INTIN(); } #endif // ==================================================================================================================== // ==================================================================================================================== // ==================================================================================================================== //---------------------------------------------------------------------------- /* =========================================================================================================================================*/ // @@@@ @@@@@ @@@@@@ @ @ @@@@ @@@@@@ @ @ @@@ @ @ @@@@@@ // @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @ @ // @@@@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ // @ @@@@@ @ @ @@ @ @ @ @ @ @ @ @ @ @ // @ @ @ @ @@ @@ @ @ @ @ @ @ @ @@ @ // @@@@ @ @@@ @ @ @@@@ @@@ @ @ @@@ @ @ @@@ // ---------------- EP2 Device-To-Host stream ------------------ // usb_EP2_tx_int_func - вызывается после отправки данных из буфера // конечной точки Ep5 (Bulk-In) хосту или ответа ему NAK. Самый первый // Bulk-In токен всегда завершается NAKом, если данные в буфер загружаются // только в этом прерывании. // void usb_EP2_tx_int_func(USB_DEVICE_INFO * udi) { /* // ------------------------------------------------------------------- // USB_INTERRUPT_DISABLE_BULKIN_NAK - запрещает прерывания от всех Bulk-In // точек по NAK. Это делается для того, чтобы в случае прихода несвоевременного // Bulk-IN пакета (раньше Bulk-Out пакета) это прерывание не портило нам жизнь, // останавливая основную программу - и, в свою очередь, останавливая обработку // события прихода данных Bulk-Out // читаем статус только что отправленного пакета int ep_status = usb_lpc_cmd_read(CMD_EP_SELECT | USB_EP_PHY_ADDRESS_BULK_IN); if( ep_status & ( 1<<1 )) // если мы ответили STALL-ом { int error = usb_getlasterror(); udi->BulkRespondStatus.INTransferInProgress = FALSE; //передача завершена udi->BulkRespondStatus.INTransferTerminating = FALSE; } // // ------------------------------------------------------------------- */ USB_INTERRUPT_CLEAR_BULKIN(); // Сброс прерывания, чтоб не щелкало usb_EP2_tx_func__( udi ); } // volatile size_t debug_call_1 = 0; //------------------------------------------------------------------------------------------------------------------------------------------ // @@@@ @@@@@ @@@@@@ @ @ @@@@ @@@@@@ @ @ @@@@ @@@@ @ @ @@@@@ @ @@@@ @@@@@@ @@@@ // @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @@ @ @ @ @ @ @ @ @ // @@@@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @ @ @ @ @@@@@@ @ @@@@@@ // @ @@@@@ @ @ @@ @ @ @ @ @ @ @ @ @ @ @@@@@ @ @ @ @ // @ @ @ @ @@ @@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ // @@@@ @ @@@ @ @ @@@@ @@@ @ @ @@@@ @@@@ @ @ @ @@@@@@ @@@@ @@@ @@@@ void usb_EP2_tx_func__(USB_DEVICE_INFO * udi) { //- -------------------------------------------------------------------------------------------------- USB_EP_STATUS * bulk_status = (USB_EP_STATUS *) &udi->EPBulkStatus; USB_BULKRESPOND_STATUS * pBulkRespond = (USB_BULKRESPOND_STATUS *) &udi->BulkRespondStatus; USB_BULKMESSAGE_STATUS * pBulkMessage = (USB_BULKMESSAGE_STATUS *) &udi->BulkMessageStatus; USB_USBTMC_CLASS_STATUS * pUSBTMCStatus = (USB_USBTMC_CLASS_STATUS*) &udi->usbtmcStatus; USB_PIPE_ENTRY_IN * pInPipe = (USB_PIPE_ENTRY_IN *) &bulk_status->InPipe; //- -------------------------------------------------------------------------------------------------- volatile unsigned int ep_status; volatile unsigned int ep_errorcode; int bytes; //- -------------------------------------------------------------------------------------------------- // bTag запроса и ответа не совпадают. Ответ будет не корректным if( pInPipe->dwLength > 0 && (pBulkRespond->bTag != pBulkMessage->bTag) ) { ep_status = usb_lpc_cmd_read( CMD_EP_SELECT | USB_EP_PHY_ADDRESS_BULK_IN ); if( (!(ep_status & (1<<4))) && ( ep_status&((1<<5)|(1<<6))) ) // ответили не NAK-ом, а данными, и данные еще остались в одном из буферов { usb_ep_clear_buffers( USB_EP_LOG_ADDRESS_BULK_IN ); } pInPipe->dwLength = 0; // возможно раньше чем Bulk-Out пришел Bulk-IN. return; } //- ---------------------------------------------------------------------------------- if( pInPipe->dwLength > 0 ) { //USB_BULKRESPOND_STATUS debug_test_brs; //USB_PIPE_ENTRY_IN debug_test_ip; // //memcpy( &debug_test_brs, pBulkRespond, sizeof(debug_test_brs) ); //memcpy( &debug_test_ip, pInPipe, sizeof(debug_test_ip) ); pBulkRespond->INTransferInProgress = TRUE; // ------------------------------------------------------------------------------------ // минимальное из InPipe.dwLength и USB_MAX_PACKET2 bytes = (pInPipe->dwLength > USB_MAX_PACKET2)? USB_MAX_PACKET2:pInPipe->dwLength; // ------------------------------------------------------------------------------------ //#error При уменьшении выходного буфера до 96 байт, каждая точка занимала 38 байт, которые и отправлялись\ но иногда здесь bytes>64, почему? изза этого уходит short пакет, причем раньше, чем\ сама функция передаст все данные //--------------------------------------------------------------------------------- // запись в буфер конечной точки bytes = usb_ep_write( USB_EP_LOG_ADDRESS_BULK_IN, (BYTE*)pInPipe->pData, bytes); //--------------------------------------------------------------------------------- // -------------------------------------------------------------------------- // увеличиваем счетчик переданых байт для запроса CHECK_ABORT_BULK_IN_STATUS pBulkRespond->nBytesSent += bytes; // а также изменяем данные Pipe pInPipe->dwLength -= bytes; // -- количество байт к передаче (текущая Transfer) pInPipe->dwAllLength -= bytes; // -- всего байт к передаче pInPipe->pData += bytes; // ++ указатель передачи (RD) pBulkRespond->dwDeviceOut -= bytes; // -- всего байт которые поставило в очередь устройство (размер вых буфера Device) pBulkRespond->bEndOfMessage = FALSE; // -------------------------------------------------------------------------- // ----------------------- вызов Callback функции по завершению передачи буфера --------------- if( pBulkRespond->dwDeviceOut == 0 || pInPipe->dwLength == 0) // если буфер опустел (конец Transfer) if( pBulkRespond->bIsLastTransfer == FALSE ) // если это не последяя Transfer if( pInPipe->pfTransferEndHandler != NULL ) // если есть CallBack { // ------------------------------------------------------------------------- pBulkRespond->INTransferInProgress = FALSE; // Transfer - завершена if( pBulkRespond->INTransferTerminating == TRUE ) // если мы ждали ... { pBulkRespond->INTransferTerminating = FALSE; // ... завершения передачи pUSBTMCStatus->USBTMC_status = STATUS_SUCCESS;} // ------------------------------------------------------------------------- //#error вызвали. он модифицировал нам dwLength (и вставил BULKINHEADER со старым bTag!!!) // debug_call_1 ++; pInPipe->pfTransferEndHandler ( udi ); // обработчик завершения Transfer } // -------------------------------------------------------------------------------------------- // --------------------------------------- if(pBulkRespond->dwDeviceOut == 0) GPIB_CLR_MAV(); // --------------------------------------- // --------------------------------------------------------------------------------------------------------------------------- // Если всетаки pInPipe->dwLength === 0, нужно завершить передачу Short пакетом // ---------------------------------------------------------------------------- bulk_status->shortpacket = FALSE; // ставить в очередь Short пакет не требуется по умолчанию //#error проверить, верно ли условие установки bulk_status->shortpacket=true, подозрительно, что bytes присваивается ДО вызова pfTransferEndHandler, а потом оно анализируется...\ А если pfTransferEndHandler выдаст данные и shortпакет не нужен? // если требуется прервать передачу - отпавляем short-пакет if( pBulkRespond->INTransferTerminating ) bulk_status->shortpacket = TRUE; // если только что отправленные - последние во всей посылке USBTMC - отпавляем short-пакет if( (pInPipe->dwLength == 0) && (bytes == USB_MAX_PACKET2) ) { // данных на передачу в канале не осталось (pInPipe->dwLength = 0) // последняя посылка в EP оказалась равна максимальному размеру EP (bytes == USB_MAX_PACKET2) // вроде как надо отправить short-пакет .... // 03/09/18. хост управляет количеством считываемых данных. Даже если // уже pBulkRespond->dwDeviceOut > 0, передача BulkIN закончилась, хост должен // прислать следующий запрос на BulkIN. А эту передачу необходимо закончить // short-пакетом. bulk_status->shortpacket = TRUE; } // --------------------------------------------------------------------------------------------------------------------------- } else { // =============== QUEUE SHORT PACKET ==================== if( bulk_status->shortpacket == TRUE ) { bulk_status->shortpacket = FALSE; bulk_status->shortpacketsending = TRUE; usb_ep_write( USB_EP_LOG_ADDRESS_BULK_IN, (BYTE*)pInPipe->pData, 0); // честный балк ждет от нас Short пакета. } else { //NAK в следующем IN токене if( bulk_status->shortpacketsending == TRUE ) { bulk_status->shortpacketsending = FALSE; bulk_status->shortpacket = FALSE; } // ======================================================= pBulkRespond->INTransferInProgress = FALSE; if( pBulkRespond->INTransferTerminating == TRUE ) // если мы ждали завершения передачи { pBulkRespond->INTransferTerminating = FALSE; pUSBTMCStatus->USBTMC_status = STATUS_SUCCESS; } //--------------------------------------------------- // -- сбрасываем Message Available бит, все передали. if(pBulkRespond->dwDeviceOut == 0) { GPIB_CLR_MAV(); } // see USB488 spec ,rev 1.0, 2003, page 13, 4.3.1.3 //--------------------------------------------------- } } } // ---------------- ------------------------- ------------------ /* =========================================================================================================================================*/ /* =========================================================================================================================================*/ // @@@@ @@@@@ @@@@@@ @ @ @@@@ @@@@@ @ @ @@@ @ @ @@@@@@ // @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @ @ // @@@@@@ @ @ @ @ @ @ @ @@@@@ @ @ @ @ @ @ // @ @@@@@ @ @ @@ @ @ @ @ @ @ @ @ @ @ @ // @ @ @ @ @@ @@ @ @ @ @ @ @ @ @ @@ @ // @@@@ @ @@@ @ @ @@@@ @ @@ @ @ @@@ @ @ @@@ // ---------------- EP2 Host-To-Device stream ------------------ void usb_EP2_rx_int_func(USB_DEVICE_INFO * udi) { USB_INTERRUPT_CLEAR_BULKOUT(); usb_EP2_rx_func__ ( udi ); } //============================================================================================================================================================================================= // @@@@@ @ @ @ @ @ @@@@@ @@@@ @@@@ @@@ @@@@ @ @ @@@@ // @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ // @@@@@ @ @ @ @@@@ @@@@@ @@@@@@ @ @ @@@@@@ @ @ @@@@@@ // @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ // @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ // @@@@@ @@@@ @@@@@@ @ @ @ @@ @@@@ @@@@ @@@ @@@@ @@ @@@@ void usb_EP2_rx_func__(USB_DEVICE_INFO * udi) { //------------------------------------------------------------------------------------------ unsigned int len; unsigned int treshold; volatile unsigned int ep_status; int sibytes_limit; int iDoubleBufferPeekAttempts; // сколько раз можно при bNeedHaltEndpoint забирать данные из второго буфера FIFO //------------------------------------------------------------------------------------------ BOOL rc; BOOL bNeedHaltEndpoint = FALSE; // условие остановки Bulk-End point. see USBTMC spec, rev 1.0, page 11, "3.2.2.4 Halt" BOOL bItIsFirstPacket = FALSE; // это первый пакет передачи, содержащий заголовок BOOL bHostToDevice_Direction; // если TRUE, стадия данных направлена от Host -> Device, запись в устройство BOOL bBufferOverflow = FALSE; // TRUE указывает, произошло ли переполнение входного буфера BOOL bBuffer1Full; BOOL bBuffer2Full; BOOL bSkipPacket; BOOL bGenError = FALSE; //------------------------------------------------------------------------------------------ USB_PIPE_ENTRY_IN * pPipeIn = (USB_PIPE_ENTRY_IN *) &udi->EPBulkStatus.InPipe; // HostIN, DeviceOUT USB_PIPE_ENTRY_OUT * pPipeOut = (USB_PIPE_ENTRY_OUT*) &udi->EPBulkStatus.OutPipe; // HostOUT, DeviceIN //------------------------------------------------------------------------------------------ USB_BULKMESSAGE_STATUS * pBulkMessage = (USB_BULKMESSAGE_STATUS*) &udi->BulkMessageStatus; USB_BULKRESPOND_STATUS * pBulkRespond = (USB_BULKRESPOND_STATUS*) &udi->BulkRespondStatus; BULKOUT_HEADER * pBulkOutHeader; // BYTE * pBulkData; // //------------------------------------------------------------------------------------------ iDoubleBufferPeekAttempts = 1; // сколько раз можно при bNeedHaltEndpoint забирать данные из второго буфера FIFO // --- проверка обоих буферов EP while((bNeedHaltEndpoint==FALSE) || (bNeedHaltEndpoint && iDoubleBufferPeekAttempts--)) // даже если bNeedHaltEndpoint второй пакет похоже нужно забрать (DoubleBuffer) { // ------------------------------------------------------------------------------------------------------------------------ ep_status = usb_lpc_cmd_read(CMD_EP_SELECT | USB_EP_PHY_ADDRESS_BULK_OUT); // Phy EP4 - Host-to-Device Direction (Host OUT) bBuffer1Full = (ep_status & (1<<5)); bBuffer2Full = (ep_status & (1<<6)); if( bBuffer1Full==FALSE && bBuffer2Full == FALSE ) break; // ------------------------------------------------------------------------------------------------------------------------ // ---- Есть данные в буфере if( pBulkMessage->bBulkHeaderRecieved == FALSE || bBufferOverflow == TRUE) // если не принят заголовок или переполнение буфера { pPipeOut->pData = pPipeOut->pDefaultBuffer; pPipeOut->dwLength = 0; pBulkMessage->nBytesRecieved = 0; pBulkMessage->bBulkHeaderRecieved = FALSE; // sibytes_limit = -1; // нет лимита } else { // ограничиваем размер считываемых байт в буфер. при превышении лимита байты просто достаются из FIFO и теряются sibytes_limit = USB_MAX_BULKOUT_BUFFERSIZE - pBulkMessage->nBytesRecieved - sizeof(BULKOUT_HEADER); // длинна заголовка в nBytesRecieved не входит, но заголовок то тоже нужно хранить if( sibytes_limit >= USB_MAX_PACKET2) sibytes_limit = -1; //есть смысл ограничивать количество байт тогда, когда оно больше чем USB_MAX_PACKET2. // если sibytes_limit скажем 500, не нужно посылать 500, потому что у точки всяко меньше: USB_MAX_PACKET2 } // ----------------------------- Освобождение FIFO буфера -------------------------------------------------------- len = usb_ep_read( USB_EP_LOG_ADDRESS_BULK_OUT, pPipeOut->pData, sibytes_limit ); // запись буфера FIFO по указателю записи // если заголовок не принят, запись идет в начало буфера //------------------------------------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------------------------------------- bBufferOverflow = (( (sibytes_limit >=0 ) && ( len > sibytes_limit ) ) )?TRUE:FALSE; // переполнение буфера bBufferOverflow = bBufferOverflow || bNeedHaltEndpoint; if(bBufferOverflow == TRUE && bGenError == FALSE) { bGenError = TRUE; usbtmc_GenRecieveError( udi ); } //------------------------------------------------------------------------------------------------------------------------------- //---------------- Инициализация указателей ------------------------------------------------------------------------------------- pBulkData = pPipeOut->pData; pBulkOutHeader = (BULKOUT_HEADER*) pPipeOut->pData; //------------------------------------------------------------------------------------------------------------------------------- // -- определяем порог количества байт if(pBulkMessage->bBulkHeaderRecieved != TRUE) treshold = (USB_MAX_PACKET2bBulkHeaderRecieved == FALSE, // то непременно принимаемые данные должны начаться с этого заголовка, а данные некорректны по // размеру. Значит имеет место рас-синхронизация Bulk-Out - данные будут отброшены // -------------------------------------------------------------------------------------------- if(len>=treshold && bBufferOverflow==FALSE) { // see USBTMC spec, rev 1.0, 2003, page 6, cipfer 3. Если хост пришлет два Bulk-Out header, второй опознается как данные если флаг установлен // #### -------------- требуется принять заголовок Bulk-Out, если он еще не принят if(pBulkMessage->bBulkHeaderRecieved!= TRUE || pBulkMessage->nBytesRecieved == 0 ) { // -------- заголовок принят: след посылка рассматривается как данные ------ pBulkMessage->bBulkHeaderRecieved = TRUE; // ------------------------------------------------------------------------- // ----------- заполняем структуру USBTMC сообщения ---------------------------------------------------------- pBulkMessage->MsgID = pBulkOutHeader->MsgID; // принято сообщение USBTMC pBulkMessage->bTagLast = pBulkMessage->bTag; // Предыдущий тег сообщения, если сообщение разделено на неск. передач ( передач, а не транзакций ) pBulkMessage->bTag = pBulkOutHeader->bTag; // текущий тег сообщения, если сообщение разделено на неск. передач ( передач, а не транзакций ) pBulkMessage->bEOM = (pBulkOutHeader->stCommandMessage.bmTransferAttributes & USBTMC_BITMAP_EOM); // ----------------------------------------------------------------------------------------------------------- // ---- определяем направление стадии данных (запрос из устройства или запись в него на основнии кода запроса) ---- bHostToDevice_Direction = usbtmc_parse( udi, TRUE ); // псевдо вызов с флагом возвращает направление // ---------------------------------------------------------------------------------------------------------------- if( bHostToDevice_Direction ){ // Host(OUT) -> (IN)Device // -- получаем длинну посылки: see usbtmc.h, Appendix 1 pPipeOut->dwLength = pBulkOutHeader->stCommandMessage.TransferSize; // -- OutPipe.dwLength --- длинна виртуального массива данных pBulkData, pBulkMessage->OutTransferSize = pBulkOutHeader->stCommandMessage.TransferSize; // -- который может разбиваться на части в разных транзакциях и передачах } else { // Host(IN) <- (OUT)Device pPipeIn->dwLength = 0; // модифицируется в REQUEST_DEP_DEV_MSG_IN pPipeOut->dwLength = 0; // направление стадии данных Device->Host pBulkRespond->InTransferSize = pBulkOutHeader->stCommandMessage.TransferSize; // -- сколько хост хочет прочитать } // проверяем корректность заголовка, если bTag != bTagInverse, то пришли неверные данные. заголовок некорректный и будет отброшен if( !((pBulkOutHeader->bTag ^ pBulkOutHeader->bTagInverse) == 0xFF) ) pBulkMessage->bBulkHeaderRecieved = FALSE; if( pBulkMessage->bBulkHeaderRecieved == TRUE) { pBulkData += sizeof(BULKOUT_HEADER); // -- прыгаем к началу данных, следуюших ЗА заголовком len -= sizeof(BULKOUT_HEADER); // -- len == количество байт ДАННЫХ транзакции после заголовка bItIsFirstPacket = TRUE; // -- указывает что это первая транзакция сообшения (содержит заголовок) pBulkMessage->pData = pBulkData; // -- сохраняем указатель на данные if( pPipeOut->dwLength <= USB_MAX_BULK_PAYLOAD ) { // если посылка НЕ разбивается на несколько транзакций pBulkMessage->nBytesRecieved = 0; // увеличивается дальше } else { // если посылка разбивается на несколько транзакций pBulkMessage->nBytesRecieved = 0; // увеличивается дальше pBulkMessage->OUTTransferInProgress = TRUE; // показывает, что происходит длительная передача данных - нужно для обработки запроса INITIATE_ABORT_BULK_OUT } } // if ( HEADER RECIEVED ) } else { // fixed 29/08/18 bHostToDevice_Direction = usbtmc_parse( udi, TRUE ); // псевдо вызов с флагом возвращает направление } //------------------------------------------------------------------------------------------------------------- if( pBulkMessage->bBulkHeaderRecieved == TRUE ) { //----------------------------------------------------------------------------------------------- if( pBulkMessage->nBytesRecieved + len > USB_MAX_BULKOUT_BUFFERSIZE ) // защита { len = USB_MAX_BULKOUT_BUFFERSIZE - pBulkMessage->nBytesRecieved; // =============================== // // >>> Память переполнена <<< // // ------------------------------- // // __ // // / \ Память переполнена // // | X | В буфере нет места // // \ __ / для кеширования дан- // // ных. // // ------------------------------- // } pBulkData += len; //передвигаем указатель записи. По завершении нужно записать этот указатель в pPipeOut->pData pBulkMessage->nBytesRecieved +=len; // увеличиваем счетчик принятых байт //----------------------------------------------------------------------------------------------- // see USBTMC spec, rev 1.0, 2003, page 11, table 7, point 6 if(len > pPipeOut->dwLength) if(len - pPipeOut->dwLength > 3) // it is not aligment bytes bNeedHaltEndpoint = TRUE; //------------------------------------------------------------------ // Выясняем, сколько данных осталось принять // в pBulkEPStatus->OutPipe.dwLength содержится ожидаемое количество байт сообщения, которые еще не приняты if( bHostToDevice_Direction ) pPipeOut->dwLength = (len > pPipeOut->dwLength)? 0: pPipeOut->dwLength-len; //------------------------------------------------------------------ BOOL bShortPacketRecieved = ((len+((bItIsFirstPacket)?sizeof(BULKOUT_HEADER):0)) < USB_MAX_PACKET2)?TRUE:FALSE; //------------------------------------------------------------------------------------------------- // see USBTMC spec, rev 1.0, 2003, page 6, cipfer 4, "The device must consider the transfer complete when it has recieved and processed" // - exactly the amount of data expected : udi->EPBulkStatus.OutPipe.dwLength == 0 // - a packet with payload size less wMaxPacketSize: len < USB_MAX_PACKET2 // - только len - длинна всего пакета вместе с заголовком //see USBTMC spec, rev 1.0, 2003, page 11, table 7, point 4 if( bShortPacketRecieved && pPipeOut->dwLength != 0) // dwLength - еще осталось принять bNeedHaltEndpoint = TRUE; // ------------------------------------------------------------------------------------ // -- пропускаем пакет если bNeedHaltEndpoint всегда, за искключением: bBufferOverflow==TRUE && iDoubleBufferPeekAttempts == 0 bSkipPacket = bNeedHaltEndpoint; if(bSkipPacket) { bSkipPacket = (bBufferOverflow==FALSE); if( bSkipPacket ) bSkipPacket = (iDoubleBufferPeekAttempts > 0); // обрабатываем СЛЕДУЮЩИЙ пакет, после пакета переполнившего буффер } // ------------------------------------------------------------------------------------ if( !bSkipPacket && (pPipeOut->dwLength == 0 || bShortPacketRecieved)) // если сообщение полностью принято { pBulkMessage->OUTTransferInProgress = FALSE; // ===================================================================== // >>> О буфере и размере ответного сообщения <<< // --------------------------------------------------------------------- // ____ Внимание! Используется буфер размером 1,5Кб, сообщения, // / \ размером больше 1,5Кб отправлять нельзя! Так как отправка // | X | происходит по прерыванию и указатели сдвигаются по прерыванию, // \____/ в usbtmc_parse следует быть осторожнее с размером передаваемых // данных. Если записать по указателю pData данных больше чем 1,5Кб // все пройдет незаметно и данные вылезут за границу массива и пойдет катавасия // ===================================================================== if( bHostToDevice_Direction) // если DEV_DEP_MSG_OUT чистим буфер, он заполнится данными, а когда придет REQUEST_DEV_DEP_MSG_IN уже чистить нельзя, там ответ! { usb_reset_pipe_status( pPipeIn ); usbtmc_flush_buffer ( USB_EP_LOG_ADDRESS_BULK_IN, pPipeIn ); } rc = usbtmc_parse( udi, FALSE ); // Разбираем сообщение if( rc == TRUE ) { // ЕСЛИ пришел DEV_DEP_MSG_OUT - данные в выходном буфере (pPipeIn) но длинна pPipeIn->dwLength равна нулю. Она изменится на валидную в REQUEST_DEP_DEV_MSG_IN // ЕСЛИ пришел REQUEST_DEP_DEV_MSG_IN - данные в буфере, количество отправляемых данных лежит в переменной eps->InPipe.dwLength //if( bNeedHaltEndpoint ) //!#! // pPipeIn->dwLength = 0; // сообщение распарсено, но так как переполнение было, данных мы не отдадим! Нужно для INITIATE_ABORT_BULK_IN } else bNeedHaltEndpoint = TRUE; // see USBTMC spec, rev 1.0,2003, page 10, table 7, index =2 pBulkMessage->bBulkHeaderRecieved = FALSE; // сбросить флаг заголовка - теперь надо принять следующий заголовок, поток данных закончился } else { // сообщение приянято не полностью // ждем... } pPipeOut->pData = pBulkData; // сохраняем позицию записи //-------------------------------------------------------------------------------------------------- } else { //see USBTMC spec, rev 1.0, 2003, page 11, "3.2.2.4 Halt": // + "The device may Halt the endpoint for reasons other than those specified in Table 7." // + The device does not receive a complete Bulk-OUT Header in the first transaction of the transfer. bNeedHaltEndpoint = TRUE; } //--------------------------------------------------------------------------------------------* // ============ # INFO # ============= # ============ # =========== # =========== # ======== // // len - переменная, содержащая количество байт данных в сообщении, по адресу pBulkData // udi->EPBulkStatus.OutPipe.dwLength - переменная, содержащая общее ОСТАВШЕЕСЯ количество байт посылки, которые требуется принять в следующих транзакциях сообщения // // ============ # ---- # ============= # ============ # =========== # =========== # ======== // ####...........................................................................................................#### // ################################################################################################################### }// if(len>=treshold) ... else { // see USBTMC spec, p 10, table 7 // see USBTMC spec, p 6, point 4: "If the last data payload is wMaxPacketSize, the Host should not send a zero-length packet", // should - не следует, но может и послать, поэтому игнорим нулевой пакет if(len>0) bNeedHaltEndpoint = TRUE; } } USB_INTERRUPT_ENABLE_BULKOUT(); //--------------------------------------- if( bNeedHaltEndpoint ) /* --------------------------------------- */ // см usbtmc.c :: usbtmc_HOOK_control_out() // abort() произойдет как только хост очистит точку STALL->UNSTALL. // Abort() также происзойдет если хост пришлет initiate_abort_bulk_out() или initiate_clear() // поэтому смысла тут делать abort() нет, к тому же, нужно сохранить состояние, на случай если хост // все же пришлет initiate_abort_bulk_out и мы ему ответим SUCCESS а не STATUS_TRANSFER_NOT_IN_PROGRESS usb_stall_ep( USB_EP_LOG_ADDRESS_BULK_OUT, 0x01 ); // пусть хост присылает INITIATE_ABORT! /* --------------------------------------- */ } //---------------------------------------------------------------------------- void usb_ep_clear_buffers( TENDPOINT_PHY_ADDRESS ep_num_physical ) { int ep_status = usb_lpc_cmd_read(CMD_EP_SELECT | ep_num_physical); if( ep_status & 0x60 ) { usb_lpc_cmd(CMD_EP_CLEAR_BUFFER); usb_lpc_cmd(CMD_EP_CLEAR_BUFFER); ep_status = usb_lpc_cmd_read(CMD_EP_SELECT | ep_num_physical); usb_lpc_cmd(CMD_EP_CLEAR_BUFFER); } } #endif