| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116 |
- #include "usbd_usbtmc.h"
- #include "usbd_desc.h"
- #include "usbd_ctlreq.h"
- #include "usbd_usbtmc_desc.h"
- // @g_husbtmc:
- // Due to some methods can not use USBD_HandleTypeDef parameter, it is required
- // to get the device handle @pdev in the other way: the class handle contains the
- // "backward" pointer to the device handle @pdev, and in the same time,
- // the device handle contains the class handle @pClassData.
- // Metods refers to @g_husbtmc: USBD_USBTMC_DataIn_BeginSend, USBD_USBTMC_StallEP, USBD_USBTMC_ClearEP
- static USBD_USBTMC_HandleTypeDef * g_husbtmc = NULL;
- static uint8_t USBD_USBTMC_Init (USBD_HandleTypeDef *pdev,
- uint8_t cfgidx);
- static uint8_t USBD_USBTMC_DeInit (USBD_HandleTypeDef *pdev,
- uint8_t cfgidx);
- static uint8_t USBD_USBTMC_Setup (USBD_HandleTypeDef *pdev,
- USBD_SetupReqTypedef *req);
- static uint8_t USBD_USBTMC_Error (USBD_HandleTypeDef *pdev,
- uint8_t epnum);
- static uint8_t USBD_USBTMC_EP0_RxReady (USBD_HandleTypeDef *pdev, size_t * );
- static uint8_t USBD_USBTMC_EP0_TxSent (USBD_HandleTypeDef *pdev, size_t * );
- static uint8_t USBD_USBTMC_DataIn (USBD_HandleTypeDef *pdev, uint8_t );
- static uint8_t USBD_USBTMC_DataOut (USBD_HandleTypeDef *pdev, uint8_t, bool );
- /* Vendor interface class callbacks structure */
- const USBD_ClassTypeDef USBD_USBTMC =
- {
- .Init = USBD_USBTMC_Init,
- .DeInit = USBD_USBTMC_DeInit,
- .Error = USBD_USBTMC_Error,
- .Setup = USBD_USBTMC_Setup,
- .EP0_TxSent = USBD_USBTMC_EP0_TxSent,
- .EP0_RxReady = USBD_USBTMC_EP0_RxReady,
- .DataIn = USBD_USBTMC_DataIn,
- .DataOut = USBD_USBTMC_DataOut,
- .SOF = NULL,
- .pDesc = &USBD_USBTMC_DescriptorHandlers,
- };
- // @USBD_USBTMC_GetDescriptorHandlers
- // Returns the GetDesciptor handlers set pointer for current class
- const USBD_DescriptorsTypeDef * USBD_USBTMC_GetDescriptorHandlers()
- {
- if( NULL != g_husbtmc )
- return g_husbtmc->pdev->pClass->pDesc;
- return NULL;
- }
- /**
- * @brief USBD_USBTMC_Init
- * Initialize the Vendor interface
- * @param pdev: device instance
- * @param cfgidx: Configuration index
- * @retval status
- */
- static uint8_t USBD_USBTMC_Init (USBD_HandleTypeDef *pdev,
- uint8_t cfgidx)
- {
- uint8_t ret = USBD_OK;
- USBD_USBTMC_HandleTypeDef *husbtmc;
- pdev->pClassData = USBD_malloc(sizeof(USBD_USBTMC_HandleTypeDef));
-
- if(pdev->pClassData == NULL)
- {
- ret = USBD_FAIL;
- }
- else
- {
- husbtmc = (USBD_USBTMC_HandleTypeDef*) pdev->pClassData;
-
- husbtmc->pdev = pdev; // for @USBD_USBTMC_DataIn_BeginSend()
- g_husbtmc = husbtmc; // for @USBD_USBTMC_DataIn_BeginSend()
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
-
- /* Open EP1 OUT */
- USBD_LL_OpenEP(pdev,
- USBTMC_BULKOUT_EP,
- USBD_EP_TYPE_BULK,
- USBTMC_DATAOUT_MAX_PACKET_SIZE);
-
- pdev->ep_out[ (USBTMC_BULKOUT_EP) & 0x7F ].maxpacket = USBTMC_DATAOUT_MAX_PACKET_SIZE;
- //USBD_LL_ClearStallEP( pdev, USBTMC_BULKOUT_EP );
- /* Open EP1 IN */
- USBD_LL_OpenEP(pdev,
- USBTMC_BULKIN_EP,
- USBD_EP_TYPE_BULK,
- USBTMC_DATAIN_MAX_PACKET_SIZE);
-
- pdev->ep_in[ (USBTMC_BULKIN_EP) & 0x7F ].maxpacket = USBTMC_DATAIN_MAX_PACKET_SIZE;
- //USBD_LL_ClearStallEP( pdev, USBTMC_BULKIN_EP );
- /* Open EP2 IN */
- USBD_LL_OpenEP(pdev,
- USBTMC_INTERRUPTIN_EP,
- USBD_EP_TYPE_INTR,
- USBTMC_DATAIN_MAX_PACKET_SIZE);
-
- // USBD_LL_ClearStallEP( pdev, USBTMC_INTERRUPTIN_EP );
- pdev->ep_in[ (USBTMC_INTERRUPTIN_EP) & 0x7F ].maxpacket = USBTMC_INTIN_MAX_PACKET_SIZE;
- // Update PMA addresses for endpoints
- USBD_LL_UpdatePMA( pdev );
- usb_create_transfer( &husbtmc->ep0_tx_transfer,
- &husbtmc->ep0_tx_buffer[0],
- sizeof(husbtmc->ep0_tx_buffer),
- NULL, pdev );
-
- usb_create_transfer( &husbtmc->ep0_rx_transfer,
- &husbtmc->ep0_rx_buffer[0],
- sizeof(husbtmc->ep0_rx_buffer),
- NULL, pdev );
- usb_create_transfer( &husbtmc->ep1_tx_transfer,
- &husbtmc->ep1_tx_buffer[0],
- sizeof(husbtmc->ep1_tx_buffer),
- NULL, pdev );
-
- usb_create_transfer( &husbtmc->ep1_rx_transfer,
- &husbtmc->ep1_rx_buffer[0],
- sizeof(husbtmc->ep1_rx_buffer),
- NULL, pdev );
- usb_create_transfer( &husbtmc->ep2_tx_transfer,
- &husbtmc->ep2_tx_buffer[0],
- sizeof(husbtmc->ep2_tx_buffer),
- NULL, pdev );
-
- if( 0 == pUserIface->fUsbInit() )
- {
- // Prepare BulkOUT endpoint for the next transaction
- USBD_COMMON_DataOutBegin( pdev, USBTMC_BULKOUT_EP, &husbtmc->ep1_rx_transfer );
- if( USBD_STATE_DEFAULT == pdev->dev_state ) // useless
- {
- if( NULL != pUserIface->fResetEvent )
- {
- pUserIface->fResetEvent();
- }
- }
- if( pdev->dev_state == USBD_STATE_CONFIGURED )
- {
- if( NULL != pUserIface->fSetIface )
- {
- //--------------------------------------------------------------------------------------
- // Enumerate interface descriptors and call SetInterface callback
- uint16_t nConfDescLength = 0;
- const uint8_t * pDescBytePtr = NULL;
- #if USBD_GETDESCRIPTORS_ALTMETHOD == 0
- ret = USBD_CallGetDescriptorHandler( pdev,
- eGetDescriptorHandlerType_Config,
- &pbuf,
- &len );
- #else
- USBD_CallGetDescriptorHandlerAlt( ret, pdev, pDescBytePtr, nConfDescLength, GetConfigDescriptor );
- #endif
- if( USBD_OK == ret )
- {
- const sUSBConfigurationDescriptor_t * conf = (const sUSBConfigurationDescriptor_t *)pDescBytePtr;
-
- size_t ifidx = 0;
- while( nConfDescLength > 0 )
- {
- sUSBDescriptorHeader_t * pDescHeader = (sUSBDescriptorHeader_t*)pDescBytePtr;
-
- if( pDescHeader->bLength == 0 ) break;
-
- if( USB_DESC_TYPE_INTERFACE == pDescHeader->bDescriptorType )
- {
- const sUSBInterfaceDescriptor_t * ifdesc = (const sUSBInterfaceDescriptor_t *)pDescBytePtr;
-
- if( ! pUserIface->fSetIface( cfgidx, ifidx++, ifdesc ) )
- {
- ret = USBD_FAIL;
- break;
- }
- }
-
- nConfDescLength -= pDescHeader->bLength;
-
- pDescBytePtr += (pDescHeader->bLength);
- }
- (void)conf;
- }
- //--------------------------------------------------------------------------------------
- }
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- return ret;
- }
- /* UNUSED FUNCTION
- static const sUSBInterfaceDescriptor_t * USBD_USBTMC_SearchInterfaceDescriptor( USBD_HandleTypeDef *pdev, uint8_t cfgidx, uint8_t nIf )
- {
- //--------------------------------------------------------------------------------------
- // Enumerate interface descriptors and call ClearInterface callback
- (void)cfgidx; // to do - use cfgidx to get configuration descriptor
- uint16_t nConfDescLength = 0;
- const uint8_t * pDescBytePtr = (const uint8_t * )pdev->pClass->GetFSConfigDescriptor(&nConfDescLength);
- const sUSBConfigurationDescriptor_t * conf = (const sUSBConfigurationDescriptor_t *)pDescBytePtr;
-
- while( nConfDescLength > 0 )
- {
- sUSBDescriptorHeader_t * pDescHeader = (sUSBDescriptorHeader_t*)pDescBytePtr;
-
- if( pDescHeader->bLength == 0 ) break;
-
- if( USB_DESC_TYPE_INTERFACE == pDescHeader->bDescriptorType )
- {
- const sUSBInterfaceDescriptor_t * ifdesc = (const sUSBInterfaceDescriptor_t *)pDescBytePtr;
-
- if( ifdesc->bInterfaceNumber == nIf )
- {
- return ifdesc;
- }
- }
-
- nConfDescLength -= pDescHeader->bLength;
-
- pDescBytePtr += (pDescHeader->bLength);
- }
- //--------------------------------------------------------------------------------------
- return NULL;
- }
- */
- /**
- * @brief USBD_USBTMC_Init
- * DeInitialize the Vendor layer
- * @param pdev: device instance
- * @param cfgidx: Configuration index
- * @retval status
- */
- static uint8_t USBD_USBTMC_DeInit (USBD_HandleTypeDef *pdev,
- uint8_t cfgidx)
- {
- uint8_t ret = USBD_OK;
-
- /* DeInit physical Interface components */
- if(pdev->pClassData != NULL)
- {
- if( pdev->pUserData != NULL )
- {
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
- if( NULL != pUserIface->fClrIface )
- {
- if( ((pdev->dev_old_state == USBD_STATE_CONFIGURED)
- || (pdev->dev_old_state == USBD_STATE_SUSPENDED) )
- && ((pdev->dev_state != USBD_STATE_CONFIGURED)
- || (pdev->dev_state != USBD_STATE_SUSPENDED) ) )
- {
- //--------------------------------------------------------------------------------------
- // Enumerate interface descriptors and call ClearInterface callback
- (void)cfgidx; // to do - use cfgidx to get configuration descriptor
- uint16_t nConfDescLength = 0;
- const uint8_t * pDescBytePtr = NULL;
- #if USBD_GETDESCRIPTORS_ALTMETHOD == 0
- ret = USBD_CallGetDescriptorHandler( pdev,
- eGetDescriptorHandlerType_Config,
- &pbuf,
- &len );
- #else
- USBD_CallGetDescriptorHandlerAlt( ret, pdev, pDescBytePtr, nConfDescLength, GetConfigDescriptor );
- #endif
- if( USBD_OK == ret )
- {
- const sUSBConfigurationDescriptor_t * conf = (const sUSBConfigurationDescriptor_t *)pDescBytePtr;
- size_t ifidx = 0;
- while( nConfDescLength > 0 )
- {
- sUSBDescriptorHeader_t * pDescHeader = (sUSBDescriptorHeader_t*)pDescBytePtr;
- if( pDescHeader->bLength == 0 ) break;
- if( USB_DESC_TYPE_INTERFACE == pDescHeader->bDescriptorType )
- {
- const sUSBInterfaceDescriptor_t * ifdesc = (const sUSBInterfaceDescriptor_t *)pDescBytePtr;
-
- pUserIface->fClrIface( cfgidx, ifidx++, ifdesc );
- }
- nConfDescLength -= pDescHeader->bLength;
- pDescBytePtr += (pDescHeader->bLength);
- }
- (void)conf;
- }
- //--------------------------------------------------------------------------------------
- }
- }
- if( USBD_STATE_DEFAULT == pdev->dev_state )
- {
- if( NULL != pUserIface->fResetEvent )
- {
- pUserIface->fResetEvent();
- }
- }
-
- pUserIface->fUsbDeInit();
- g_husbtmc = NULL; // for USBD_USBTMC_DataIn_BeginSend()
- USBD_free(pdev->pClassData);
- pdev->pClassData = NULL;
- USBD_LL_CloseEP( pdev, USBTMC_BULKOUT_EP );
- USBD_LL_CloseEP( pdev, USBTMC_BULKIN_EP );
- USBD_LL_CloseEP( pdev, USBTMC_INTERRUPTIN_EP );
- }
- }
-
- return ret;
- }
- static uint8_t USBD_USBTMC_Error (USBD_HandleTypeDef *pdev, uint8_t epnum)
- {
- if(pdev->pClassData != NULL)
- {
- if( pdev->pUserData != NULL )
- {
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
-
- if( epnum == 0 )
- {
- if( NULL != pUserIface->fUsbSetup )
- {
- pUserIface->fUsbSetup( &pdev->request, false, false );
- }
- }
- else
- {
- // Call user error handler
- if( NULL != pUserIface->fDataErrHandler )
- {
- pUserIface->fDataErrHandler( epnum, 0 );
- }
- #if 0
- // // Recover EP after the error
- // USBD_USBTMC_HandleTypeDef * husbtmc = (USBD_USBTMC_HandleTypeDef*) pdev->pClassData;
- //
- // switch( epnum )
- // {
- // case USBTMC_BULKOUT_EP:
- // {
- // // Prepare BulkOUT endpoint for the next transaction
- // USBD_COMMON_DataOutBegin( pdev, USBTMC_BULKOUT_EP, &husbtmc->ep1_rx_transfer );
- // }
- // break;
- // }
- #endif
- }
- }
- }
- return USBD_OK;
- }
- /**
- * @brief USBD_USBTMC_Setup
- * Handle the class specific requests
- * @param pdev: instance
- * @param req: usb requests
- * @retval status
- */
- static uint8_t USBD_USBTMC_Setup (USBD_HandleTypeDef *pdev,
- USBD_SetupReqTypedef *req)
- {
- uint8_t ret = USBD_OK;
- USBD_USBTMC_HandleTypeDef *husbtmc = (USBD_USBTMC_HandleTypeDef*) pdev->pClassData;
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
-
- if( NULL == pUserIface->fUsbSetup )
- {
- return USBD_FAIL; // @fUsbSetup is missing
- }
- if( ! pUserIface->fUsbSetup( req, true, false ) )
- {
- return USBD_FAIL; // do not call @fUsbSetup second time
- }
- else
- {
- switch (req->bmRequest & USB_REQ_TYPE_MASK)
- {
- case USB_REQ_TYPE_CLASS : // Class I/O
- case USB_REQ_TYPE_VENDOR : // Debug, Benchmarks
- {
- if (req->wLength > 0)
- {
- if (req->bmRequest & 0x80)
- {
- #if RECREATE_CONTROL_TRANSFER_OBJ
- usb_create_transfer( &husbtmc->ep0_tx_transfer,
- &husbtmc->ep0_tx_buffer[0],
- sizeof(husbtmc->ep0_tx_buffer),
- NULL, pdev );
- #endif
- ret = USBD_COMMON_Setup_DataProcess( pdev, req, &husbtmc->ep0_tx_transfer );
- }
- else
- {
- #if RECREATE_CONTROL_TRANSFER_OBJ
- usb_create_transfer( &husbtmc->ep0_rx_transfer,
- &husbtmc->ep0_rx_buffer[0],
- sizeof(husbtmc->ep0_rx_buffer),
- NULL, pdev );
- #endif
- ret = USBD_COMMON_Setup_DataProcess( pdev, req, &husbtmc->ep0_rx_transfer );
- }
- }
- else
- {
- USBD_CtlSendStatus( pdev ); // need answer for ZeroLength requests
- }
- }
- break;
- case USB_REQ_TYPE_STANDARD:
- {
- switch (req->bRequest)
- {
- case USB_REQ_GET_INTERFACE:
- {
- if( NULL != pUserIface->fGetIface )
- {
- uint8_t nIf = req->wIndex;
- uint8_t ifalt = 0;
-
- if( pUserIface->fGetIface( pdev->dev_config, nIf, &ifalt ) )
- {
- USBD_CtlSendData (pdev, &ifalt, sizeof(ifalt));
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- break;
-
- case USB_REQ_SET_INTERFACE:
- break;
- }
- }
- break;
- default:
- break;
- }
- }
- if( ret != USBD_OK )
- {
- pUserIface->fUsbSetup( req, false, false );
- }
- return ret;
- }
- #if USBTMC_USE_COMMON_EP0RXREADY
- static uint8_t USBD_USBTMC_EP0_RxReady (USBD_HandleTypeDef *pdev, size_t * pnBytesRollback )
- {
- USBD_USBTMC_HandleTypeDef *husbtmc = (USBD_USBTMC_HandleTypeDef*) pdev->pClassData;
- return USBD_COMMON_EP0_RxReady( pdev, &husbtmc->ep0_rx_transfer, pnBytesRollback );
- }
- #else
- static uint8_t USBD_USBTMC_EP0_RxReady (USBD_HandleTypeDef *pdev, size_t * pnBytesRollback )
- {
- USBD_USBTMC_HandleTypeDef *husbtmc = (USBD_USBTMC_HandleTypeDef*) pdev->pClassData;
- USBD_EndpointTypeDef * pep = &pdev->ep_out[0];
- USBD_StatusTypeDef ret = USBD_FAIL;
- sUSBTransfer_t * rx = &husbtmc->ep0_rx_transfer;
- if( pdev->pUserData != NULL && usb_validate_transfer(rx) )
- {
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
- if( NULL != pUserIface->fUsbCtlEpRx )
- {
- size_t nBytesReceived = ((pep->rem_length > pep->maxpacket)?pep->maxpacket:pep->rem_length);
- size_t nBytesRemaining = (pep->rem_length - nBytesReceived);
- // Since the core uses raw @ep0_rx_transfer->pWriteData pointer, it is required to update the transfer information.
- // Use 'virutal write' to shift the pointer:
- usb_transfer_virtual_write( rx, nBytesReceived );
- // Check if the trasfer have enough free space for receiving another packet?
- // Or maybe it is a last packet?
- if( (usb_space_transfer(rx) < MIN(nBytesRemaining, pep->maxpacket)) || (0 == nBytesRemaining) )
- {
- // No, there no enough free space
- // Need to call user handler.
- // Retirieve actual amount of data in transfer
- size_t nBytesInTransfer = usb_count_transfer(rx);
- // Calculate current data offset
- size_t nOffset = (pep->total_length - nBytesRemaining - nBytesInTransfer);
-
- // pass the data to user
- size_t nBytesProcessed = pUserIface->fUsbCtlEpRx( &pdev->request,
- rx,
- nOffset,
- nBytesRemaining + nBytesInTransfer );
- // user can perform move semantic on transfer @rx.
- // It is valid condition if no remaining bytes left only.
- // Let's check it:
- bool bValid = usb_validate_transfer( rx );
- #warning Check
- if( 0 == nBytesRemaining || bValid )
- {
- // Actually, it does not matter, what exactly the function @fUsbCtlEpRx returns.
- // The only that matters is the amount of data in the transfer.
- // Just check the return value for zero:
- if( nBytesProcessed > 0 )
- {
- // By default ( usb_count_transfer() is ZERO ) ==> @nCompressed equals to the number of bytes in the transfer before user handler call.
- size_t nCompressed = nBytesInTransfer;
-
- // It is required that the transfer be valid only if @nBytesRemaining greater than zero
- if( bValid )
- {
- // If the transfer still contains data, it means user didn't perform full read.
- if( usb_count_transfer(rx) > 0 )
- {
- // it is required to compress the data in the transfer
- // optimize the transfer to compress stored data
- nCompressed = usb_transfer_compress( rx );
- // @bNeedPacketSpace - true if the core deadly needs at least MAX_PACKET free bytes in transfer
- bool bNeedPacketSpace = false;
- // After compressing: check if the transfer have enough space for next packet?
- if( usb_space_transfer(rx) >= MIN(nBytesRemaining, pep->maxpacket) )
- {
- // yes, ok
- ret = USBD_OK;
- }
- else
- {
- // nope, user didn't read enough data from the transfer to free enough space for next packet
- // Need to free at least MAX_PACKET free bytes in transfer
- bNeedPacketSpace = true;
- }
- // try to call user handler again:
- if( bNeedPacketSpace || (0 == nBytesRemaining) )
- {
- // Here: two reasons:
- // 1) if it is required to free MAX_PACKET bytes in transfer for next packet
- // 2) or this is a last packet: last chance to retrieve data. It is required to feed all data to user... Even if he resists!!!! >:D
- // For USB-core it does not matter if user processed all bytes or not...
- // There no incoming packets expected.
- // The only problem is to send a confirmation for this transaction.
- // As soon user process all bytes from the transfer @rx, this function returns control to the
- // core to send a confirmation.
- // Ok, lets feed user..
- while( nBytesProcessed > 0 )
- {
- nBytesInTransfer = usb_count_transfer(rx);
- size_t nLeftBytes = nBytesInTransfer + ((bNeedPacketSpace)?nBytesRemaining:0);
- size_t nOffset = (pep->total_length - nLeftBytes);
- // Call user handler, again...
- nBytesProcessed = pUserIface->fUsbCtlEpRx( &pdev->request,
- rx,
- nOffset,
- nLeftBytes );
-
- // user can perform move semantic on transfer @rx.
- // It is valid condition if no remaining bytes left only.
- // Let's check it:
- #warning Check
- if( 0 == nBytesRemaining || usb_validate_transfer( rx ) )
- {
- // ~~~ do not do this here, extra compressing possible (reduces performance) ~~ /* usb_transfer_compress( rx ); */
- // ~~~ do not do this here, extra compressing possible (reduces performance) ~~ /* nCompressed += (nBytesInTransfer - usb_count_transfer(rx)); */
- // Reason 1: (only if @bNeedPacketSpace is true)
- // check if the transfer has enough data for next packet
- if( bNeedPacketSpace
- && (usb_space_transfer(rx) >= MIN(nBytesRemaining, pep->maxpacket)) )
- {
- // Reason 1: exit, because transfer has enough free space for next packet
- // User have read data portion from the transfer, need to compress it again
- // Need to update @nCompressed variable to take in account new pointer to the free memory.
- usb_transfer_compress( rx );
- nCompressed += (nBytesInTransfer - usb_count_transfer(rx));
- ret = USBD_OK;
- break;
- }
- else
- {
- // User have read data portion from the transfer, need to compress it again
- // Need to update @nCompressed variable to take in account new pointer to the free memory.
- usb_transfer_compress( rx );
- nCompressed += (nBytesInTransfer - usb_count_transfer(rx));
- }
- // check if the transfer is still not empty
- if( 0 == usb_count_transfer(rx) )
- {
- // Reason 2: exit if transfer is empty
- // Empty! => Success (nBytesProcessed>0)
- break; // yee, at last!
- }
- }
- else
- {
- // Failed!
- ret = USBD_FAIL;
- }
- }
- // Check the last user call status
- if( 0 == nBytesProcessed )
- {
- // Failed!
- ret = USBD_FAIL;
- }
- }
- }
- else
- {
- // ~~~~~~~~~~~~ ADDED 18/04/19
- // Check if the trasfer have enough free space for receiving another packet?
- // Or maybe it is a last packet?
- if( (usb_space_transfer(rx) < MIN(nBytesRemaining, pep->maxpacket)) )
- {
- // it is required to compress the data in the transfer
- // optimize the transfer to compress stored data
- nCompressed = usb_transfer_compress( rx );
- }
- // ~~~~~~~~~~~~
- ret = USBD_OK;
- }
- }
- else
- {
- // If there no bytes left to receive
- // it is normal that the transfer is invalid (user may use move semantic)
- if( 0 == nBytesRemaining )
- {
- ret = USBD_OK;
- }
- }
- // let the core know how many excaclty bytes is required to shift the pointer back.
- if( (USBD_OK == ret) && (NULL != pnBytesRollback) )
- {
- // pass the exact number of bytes for rollback to the core
- *pnBytesRollback = nCompressed;
- }
- }
- else
- {
- // user must not return zero to proceed
- usb_reset_transfer( rx );
- ret = USBD_FAIL;
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- else
- {
- // yep, there is free space for the next packet, let's receive it
- ret = USBD_CONTINUE;
- }
- }
- }
- return ret;
- }
- #endif
- #if USBTMC_USE_COMMON_EP0TXSENT
- static uint8_t USBD_USBTMC_EP0_TxSent (USBD_HandleTypeDef *pdev, size_t * pnBytesRollback )
- {
- USBD_USBTMC_HandleTypeDef *husbtmc = (USBD_USBTMC_HandleTypeDef*) pdev->pClassData;
- return USBD_COMMON_EP0_TxSent( pdev, &husbtmc->ep0_tx_transfer, pnBytesRollback );
- }
- #else
- // USBD_USBTMC_EP0_TxSent()
- // This function is called when at least one packet had been sent to the host
- // This function continues the transmitting
- static uint8_t USBD_USBTMC_EP0_TxSent (USBD_HandleTypeDef *pdev, size_t * pnBytesRollback )
- {
- USBD_USBTMC_HandleTypeDef *husbtmc = (USBD_USBTMC_HandleTypeDef*) pdev->pClassData;
-
- USBD_EndpointTypeDef * pep = &pdev->ep_in[0];
- sUSBTransfer_t * tx = &husbtmc->ep0_tx_transfer;
- uint8_t ret = USBD_FAIL;
- if( pdev->pUserData != NULL && usb_validate_transfer(tx) )
- {
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
- if( NULL != pUserIface->fUsbCtlEpTx )
- {
- // Due to the low-level driver uses dry transfer->@pReadData pointer, the
- // tranfer object must be modified.
- size_t nBytesRequested = 0;
- if( 0 == pep->rem_length )
- {
- // Update transfer information:
- // If @pep->rem_length is zero, the last packet sent was a last packet
- // The size of the short packet is a remainder of the division the
- // full transaction size and the endpoint size.
- // If the result of operation is non zero, the last packet was a short packet.
- // If the result of operation is zero, the last packet was full packet
- size_t last_packet_size = (pep->total_length % pep->maxpacket);
- if( last_packet_size == 0 )
- {
- last_packet_size = pep->maxpacket;
- }
- usb_transfer_virtual_read( tx, last_packet_size );
- }
- else
- {
- nBytesRequested = MIN( pep->maxpacket, pep->rem_length );
- // Update transfer information:
- // If @pep->rem_length is non zero, the last packet send was a full packet.
- // The size of full packet is pep->maxpacket
- usb_transfer_virtual_read( tx, pep->maxpacket );
- }
- // // Update transfer information:
- // usb_transfer_virtual_read( tx,
- // // The variable @nBytesRequested have quite confusing name, but this argument
- // // requires the length of already sent data. Actually the number of bytes already sent
- // // is numerially equals to @nBytesRequested
- // nBytesRequested // for pep->rem_length >= pep->maxpacket: the pep->maxpacket bytes just have been sent
- // ); // for pep->rem_length < pep->maxpacket: the pep->rem_length bytes just have been sent
- //
- // If the transaction is still not completed:
- if( pep->rem_length == 0 )
- {
- // transfer full reset
- usb_reset_transfer( tx );
- ret = USBD_OK;
- }
- else
- {
- size_t nBytesLeft = usb_count_transfer( tx );
- // If the transfer has enougth data to send another packet:
- if( nBytesLeft >= nBytesRequested )
- {
- ret = USBD_CONTINUE; // ask the core to continue sending the transfer (without rollback)
- }
- else
- {
- if( nBytesLeft > 0 )
- {
- // optimize the transfer to compress stored data
-
- size_t nCompressed = usb_transfer_compress( tx );
- if( NULL != pnBytesRollback )
- {
- // pass the exact number of bytes for rollback to the core
- *pnBytesRollback = nCompressed;
- }
- }
- else
- {
- // // transfer full reset
- // usb_reset_transfer( tx );
- size_t nCompressed = usb_transfer_compress( tx );
- if( NULL != pnBytesRollback )
- {
- // pass the exact number of bytes for rollback to the core
- *pnBytesRollback = nCompressed;
- }
- }
- size_t nOffset = (pep->total_length - pep->rem_length + nBytesLeft);
- size_t nBytesProcessed = pUserIface->fUsbCtlEpTx( &pdev->request,
- tx,
- nOffset,
- pep->rem_length );
-
- // User can perform move semantic on the @tx transfer.
- // This is an error condition, let's check it:
- #warning Check
- if( usb_validate_transfer( tx ) )
- {
- // Actually, does not matter what exactly the function @fUsbCtlEpTx returns,
- // because only transfer size really matters ( usb_count_transfer() ).
- // Just check the return value for zero:
- if( nBytesProcessed > 0 )
- {
- // If more than one FULL packet is required to send:
- if( pep->rem_length >= pep->maxpacket )
- {
- // This packet must be full: transfer must contain at least @pep->maxpacket bytes
- if( usb_count_transfer( tx ) >= pep->maxpacket )
- {
- ret = USBD_OK;
- }
- }
- else
- // No, it is required to send "short packet"
- {
- // This packet must be short: transfer must contain exactly @pep->rem_length bytes
- if( usb_count_transfer( tx ) == pep->rem_length )
- {
- ret = USBD_OK;
- }
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- }
- }
- }
- return ret;
- }
- #endif
- // USBD_USBTMC_DataIn
- // Handle IN requests for Bulk or Interrupt requests
- // Note: this function is only called after the first packet sent!
- static uint8_t USBD_USBTMC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum )
- {
- USBD_USBTMC_HandleTypeDef * husbtmc = (USBD_USBTMC_HandleTypeDef*)pdev->pClassData;
-
- switch( epnum | 0x80 )
- {
- case USBTMC_BULKIN_EP:
- {
- return USBD_COMMON_DataInProcess( pdev, epnum, &husbtmc->ep1_tx_transfer );
- }
- case USBTMC_INTERRUPTIN_EP:
- {
- return USBD_COMMON_DataInProcess( pdev, epnum, &husbtmc->ep2_tx_transfer );
- }
- }
- return USBD_FAIL;
- }
- #if DATAIN_INITIATESEND_REQUIRED
- // USBD_USBTMC_DataIn_BeginSend
- // Initiates the first packet sending using virtual DataIN event
- // @bTxAlreadyPrepared - if the TX-transfer is already prepared to transmission, do not reset transfer, do not call TX-handler
- uint8_t USBD_USBTMC_DataIn_BeginSend( uint8_t epnum, bool bTxAlreadyPrepared )
- {
- USBD_USBTMC_HandleTypeDef * husbtmc = g_husbtmc; // impossible: "(USBD_USBTMC_HandleTypeDef*)pdev->pClassData"
- USBD_HandleTypeDef *pdev = husbtmc->pdev; // hack, I'm not satisfated with this hack, but it is required
- switch( epnum | 0x80 )
- {
- case USBTMC_BULKIN_EP:
- {
- return USBD_COMMON_DataIn_BeginSend( pdev, epnum, &husbtmc->ep1_tx_transfer, bTxAlreadyPrepared );
- }
-
- case USBTMC_INTERRUPTIN_EP:
- {
- return USBD_COMMON_DataIn_BeginSend( pdev, epnum, &husbtmc->ep2_tx_transfer, bTxAlreadyPrepared );
- }
- }
- return USBD_FAIL;
- }
- #endif
- // USBD_USBTMC_DataIn_ZeroSend
- // Queue zero packet in EP IN
- uint8_t USBD_USBTMC_DataIn_ZeroSend( uint8_t epnum )
- {
- USBD_USBTMC_HandleTypeDef * husbtmc = g_husbtmc; // impossible: "(USBD_USBTMC_HandleTypeDef*)pdev->pClassData"
- USBD_HandleTypeDef *pdev = husbtmc->pdev; // hack, I'm not satisfated with this hack, but it is required
- switch( epnum | 0x80 )
- {
- case USBTMC_BULKIN_EP:
- case USBTMC_INTERRUPTIN_EP:
- {
- return USBD_COMMON_DataIn_ZeroSend( pdev, epnum );
- }
- }
- return USBD_FAIL;
- }
- // USBD_USBTMC_StallEP()
- // Halt specfied data-endpoint by it's address and reset the buffer
- void USBD_USBTMC_StallEP( uint8_t epaddr )
- {
- USBD_USBTMC_HandleTypeDef * husbtmc = g_husbtmc; // impossible: "(USBD_USBTMC_HandleTypeDef*)pdev->pClassData"
- USBD_HandleTypeDef *pdev = husbtmc->pdev; // hack, I'm not satisfated with this hack, but it is required
- switch( epaddr )
- {
- case USBTMC_BULKIN_EP:
- {
- USBD_LL_StallEP( pdev, epaddr );
- usb_reset_transfer( &husbtmc->ep1_tx_transfer );
- }
- break;
- case USBTMC_BULKOUT_EP:
- {
- USBD_LL_StallEP( pdev, epaddr );
- usb_reset_transfer( &husbtmc->ep1_rx_transfer );
- }
- break;
- case USBTMC_INTERRUPTIN_EP:
- {
- USBD_LL_StallEP( pdev, epaddr );
- usb_reset_transfer( &husbtmc->ep2_tx_transfer );
- }
- break;
- }
- }
- // USBD_USBTMC_ClearEP()
- // Restore specfied halted data-endpoint by it's address and reset the buffer
- // Recover the Rx-transfer for specified endpoint
- // Restarts the receiving for the specified endpoint
- void USBD_USBTMC_ClearEP( uint8_t epaddr )
- {
- USBD_USBTMC_HandleTypeDef * husbtmc = g_husbtmc; // impossible: "(USBD_USBTMC_HandleTypeDef*)pdev->pClassData"
- USBD_HandleTypeDef *pdev = husbtmc->pdev; // hack, I'm not satisfated with this hack, but it is required
- switch( epaddr )
- {
- case USBTMC_BULKIN_EP:
- {
- usb_reset_transfer( &husbtmc->ep1_tx_transfer );
- USBD_LL_ClearStallEP( pdev, epaddr );
- }
- break;
- case USBTMC_BULKOUT_EP:
- {
- USBD_COMMON_DataOutBegin( pdev, epaddr, &husbtmc->ep1_rx_transfer );
- USBD_LL_ClearStallEP( pdev, epaddr );
- }
- break;
- case USBTMC_INTERRUPTIN_EP:
- {
- usb_reset_transfer( &husbtmc->ep2_tx_transfer );
- USBD_LL_ClearStallEP( pdev, epaddr );
- }
- break;
- }
- }
- // USBD_USBTMC_NakEP()
- // Reset hardware EP buffer and setup the end-point to Not-acknowlage mode
- // No data will be returned by EP util the data will be queued again
- void USBD_USBTMC_NakEP( uint8_t epaddr )
- {
- USBD_USBTMC_HandleTypeDef * husbtmc = g_husbtmc; // impossible: "(USBD_USBTMC_HandleTypeDef*)pdev->pClassData"
- USBD_HandleTypeDef *pdev = husbtmc->pdev; // hack, I'm not satisfated with this hack, but it is required
- switch( epaddr )
- {
- case USBTMC_BULKIN_EP:
- {
- usb_reset_transfer( &husbtmc->ep1_tx_transfer );
- USBD_LL_NakEP( pdev, epaddr );
- }
- break;
- case USBTMC_BULKOUT_EP:
- {
- usb_reset_transfer( &husbtmc->ep1_rx_transfer );
- USBD_LL_NakEP( pdev, epaddr );
- }
- break;
- case USBTMC_INTERRUPTIN_EP:
- {
- usb_reset_transfer( &husbtmc->ep2_tx_transfer );
- USBD_LL_NakEP( pdev, epaddr );
- }
- break;
- }
- }
- // USBD_USBTMC_DataOut
- // Handle OUT requests for Bulk or Interrupt requests
- static uint8_t USBD_USBTMC_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum, bool ShortPacketReceived )
- {
- USBD_USBTMC_HandleTypeDef * husbtmc = (USBD_USBTMC_HandleTypeDef*)pdev->pClassData;
- switch( epnum )
- {
- case USBTMC_BULKOUT_EP:
- {
- return USBD_COMMON_DataOutProcess( pdev, epnum, &husbtmc->ep1_rx_transfer, ShortPacketReceived );
- }
- }
-
- return USBD_FAIL;
- }
- sUSBTransfer_t * USBD_USBTMC_GetDataTxTransferHandle()
- {
- return &g_husbtmc->ep1_tx_transfer;
- }
- sUSBTransfer_t * USBD_USBTMC_GetDataRxTransferHandle()
- {
- return &g_husbtmc->ep1_rx_transfer;
- }
- sUSBTransfer_t * USBD_USBTMC_GetInterruptTxTransferHandle()
- {
- return &g_husbtmc->ep2_tx_transfer;
- }
- // USBD_USBTMC_GetTxQueuedSize
- // Returns amound of bytes queued in USBTMC IN endpoint.
- // @epaddr - USBTMC EP-IN number
- // @pCount - pointer to the value to store the packet length, can be NULL
- // Return: true if there is a queued packet in EP-IN, the length is stored in @pCount
- // false if there no queued packet in EP-IN, @pCount has not been modified
- bool USBD_USBTMC_GetTxQueuedSize( uint8_t epaddr, uint32_t * pCount )
- {
- USBD_USBTMC_HandleTypeDef * husbtmc = g_husbtmc; // impossible: "(USBD_USBTMC_HandleTypeDef*)pdev->pClassData"
- USBD_HandleTypeDef *pdev = husbtmc->pdev; // hack, I'm not satisfated with this hack, but it is required
- uint32_t len = 0;
- if( -1l == ( len = USBD_GetTxCount( pdev, epaddr ), len ) )
- {
- return false; // no packet queued in TX
- }
- if( NULL != pCount ) *pCount = len;
- return true; // return the packet len in @pCount
- }
|