| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887 |
- #include "drivers/usb/class/common/class_common.h"
- #include "app/usb/usb_transfer_flags.h" // USB_TRANSFER_FLAG_SHORTPACKET
- #include "usbd_desc.h"
- #include "usbd_ctlreq.h"
- #if DEBUG_USB > 0 // SCPI debug
- volatile uint32_t gDebugUSBEPTxBytes = 0;
- volatile uint32_t gDebugUSBEPTxLastPacket = 0;
- #endif
- // USBD_COMMON_EP0_RxReady
- // This function is called when a packet via CONTROL protocol had been received from host
- // This function continues the transmitting
- uint8_t USBD_COMMON_EP0_RxReady (USBD_HandleTypeDef *pdev, sUSBTransfer_t * rx, size_t * pnBytesRollback )
- {
- USBD_EndpointTypeDef * pep = &pdev->ep_out[0];
- USBD_StatusTypeDef ret = USBD_FAIL;
-
- 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 );
-
- 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:
- 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;
- }
- // USBD_COMMON_EP0_TxSent()
- // This function is called when at least one packet via CONTROL protocol had been sent to the host
- // This function continues the transmitting
- uint8_t USBD_COMMON_EP0_TxSent (USBD_HandleTypeDef *pdev, sUSBTransfer_t * tx, size_t * pnBytesRollback )
- {
- USBD_EndpointTypeDef * pep = &pdev->ep_in[0];
- 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:
- 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;
- }
- // USBD_COMMON_Setup_DataProcess()
- // Handler for specific vendor or class requests
- // @pdev, @pUserIface, @req and @transf MUST BE NON-NULL!
- // Do not call if @req->wLength is zero
- uint8_t USBD_COMMON_Setup_DataProcess( USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req, sUSBTransfer_t * transf )
- {
- uint8_t ret = USBD_OK;
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
- if (req->wLength > 0)
- {
- if (req->bmRequest & 0x80)
- {
- // DataIN stage preparing
- if( usb_validate_transfer( transf ) ) // TX-transfer
- {
- // First packet in the stage: reset the transfer
- usb_reset_transfer( transf );
-
- // Single-transfer mode only:
- // Whole transfer is limited by the @ep0_tx_transfer size
- size_t nBytesProcessed = pUserIface->fUsbCtlEpTx( (const tUSBSetupPacket_t*)req,
- transf,
- 0,
- req->wLength );
- // User can perform move semantic on @ep0_tx_transfer transfer
- // This is an error condition, let's check it:
- if( usb_validate_transfer( transf ) )
- {
- USBD_EndpointTypeDef * pep = &pdev->ep_in[0];
- // If SETUP data stage assumes trasmitting more than one MAX_PACKET bytes,
- // this packet must include MAX_PACKET bytes (not to be "short packet")
- size_t min_limit = ((req->wLength > pep->maxpacket)?(pep->maxpacket-1):(0));
-
- // Actually, @ep0_tx_transfer can store more data than @nBytesProcessed.
- // @nBytesProcessed: bytes processed by last @fUsbCtlEpTx call.
- // Just check it for zero:
- size_t nBytesCount = usb_count_transfer( transf );
- if( nBytesProcessed > 0 )
- {
- // Check the transfer for minimal bytes limit:
- if( min_limit < nBytesCount )
- {
- // truncate the transfer in case if the transfer size is
- // greater than requested length.
- usb_truncate_transfer( transf, req->wLength );
- USBD_CtlSendData (pdev,
- (const uint8_t *)transf->pReadData,
- req->wLength );
- }
- else
- {
- USBD_CtlSendData (pdev,
- (const uint8_t *)transf->pReadData,
- nBytesCount );
- //ret = USBD_FAIL;
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- else
- {
- ret = USBD_FAIL;
- }
-
- }
- else
- {
- // DataOUT stage preparing
- if( usb_validate_transfer( transf ) ) // RX-transfer
- {
- // Reset the RX-transfer
- usb_reset_transfer( transf );
-
- // Begin receiving first packet
- USBD_CtlPrepareRx (pdev,
- (uint8_t *)transf->pWriteData,
- req->wLength );
- }
- else
- {
- ret = USBD_FAIL;
- }
- }
- }
- else
- {
- ret = USBD_FAIL; // must be processed by caller
- }
- return ret;
- }
- #if DATAIN_INITIATESEND_REQUIRED
- // USBD_COMMON_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
- //
- // Note: e.g., is called from @USBD_USBTMC_DataIn_BeginSend
- //
- uint8_t USBD_COMMON_DataIn_BeginSend( USBD_HandleTypeDef *pdev, uint8_t epnum, sUSBTransfer_t * transf, bool bTxAlreadyPrepared )
- {
- USBD_EndpointTypeDef * pep = &pdev->ep_in[ epnum & 0x7F ];
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
- if( !bTxAlreadyPrepared )
- {
- if( NULL == pUserIface->fDataTxHandler )
- {
- // error: no user handler specified
- return USBD_FAIL;
- }
- // restore transfer
- usb_reset_transfer( transf );
- #warning SCPI: note, that setting 'short-packet' indicator is useless here
- // forward set short packet indicator:
- // (just to be compatible to @USBD_COMMON_DataInProcess function)
- usb_transfer_set_shortpacket( transf );
- // call user handler: generate virtual DataIN event
- if( ! pUserIface->fDataTxHandler( epnum, transf ) )
- {
- // error: user handler error
- return USBD_FAIL;
- }
- }
- uint16_t bytes_to_send = usb_count_transfer( transf );
- if( bytes_to_send > pep->maxpacket )
- {
- bytes_to_send = pep->maxpacket;
- }
- if( bytes_to_send == pep->maxpacket )
- {
- // this is the last packet with size equal EP size: the next packet must be zero packet
- usb_transfer_set_shortpacket( transf );
- }
- // initiate the data sending
- // Note: @total_length and @rem_length will be modified: @bytes_to_send will be stored to these fields.
- if( USBD_OK != USBD_EpSendData( pdev, (uint8_t*)transf->pReadData, bytes_to_send, epnum ) )
- {
- #if DEBUG_USB
- gDebugUSBEPTxLastPacket = bytes_to_send;
- #endif
- // error: can not send data
- return USBD_FAIL;
- }
- // perform virtual reading due to the USB Low Level have sent the data from the transfer
- usb_transfer_virtual_read( transf, bytes_to_send );
- #if DEBUG_USB > 0 // SCPI debug
- gDebugUSBEPTxBytes += bytes_to_send;
- #endif
- return USBD_OK;
- }
- #endif
- // USBD_USBTMC_DataIn_ZeroSend
- // Queue zero packet in EP IN
- //
- uint8_t USBD_COMMON_DataIn_ZeroSend( USBD_HandleTypeDef *pdev, uint8_t epnum )
- {
- USBD_EndpointTypeDef * pep = &pdev->ep_in[ epnum & 0x7F ];
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
- uint8_t dummy = 0;
- // initiate the data sending
- // Note: @total_length and @rem_length will be modified: @bytes_to_send will be stored to these fields.
- if( USBD_OK != USBD_EpSendData( pdev, &dummy, 0, epnum ) )
- {
- // error: can not send data
- return USBD_FAIL;
- }
- (void)pep, (void)pUserIface;
- return USBD_OK;
- }
- // USBD_COMMON_DataInProcess
- // Process DataIN events for Bulk and Interrupt endpoints
- //
- // Note: e.g., is called from @USBD_USBTMC_DataIn()
- //
- uint8_t USBD_COMMON_DataInProcess( USBD_HandleTypeDef *pdev, uint8_t epnum, sUSBTransfer_t * transf )
- {
- #if DEBUG_USBTMC_REQUESTS > 0
- void debug_log( uint8_t value, uint16_t value2 );
- #define DEBUG_LOG_STATE_DATAIN 0x04
- debug_log( DEBUG_LOG_STATE_DATAIN, usb_count_transfer( transf ) );
- #endif
- USBD_EndpointTypeDef * pep = &pdev->ep_in[ epnum & 0x7F ];
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
- #if !DATAIN_INITIATESEND_REQUIRED
- // Initiating the first packet sending is disabled,
- // the flow is being controlled by IRQ only,
- // so the fDataTxHandler is required.
- if( NULL == pUserIface->fDataTxHandler )
- {
- return USBD_FAIL;
- }
- #endif
-
- // Note: @total_length and @rem_length had been modified: these fields stores the length of the FIRST packet sent (USBD_EpSendData)
- // Check if is there enough data for next packet
- if( usb_count_transfer( transf ) < pep->maxpacket )
- {
- // No, the transfer does not have enough data for the full next packet
- // Check if the transfer have enough free space to store next packet?
- if( usb_space_transfer( transf ) < pep->maxpacket )
- {
- // No, the transfer must be compressed
- usb_transfer_compress( transf );
- }
- // Call user handler:
- // User shall reset Short-Packet indicator using @usb_transfer_modify_flags
- // ... routine to avoid sending short packet in case no data queued into
- // ... the transfer after successful call.
- if( ! pUserIface->fDataTxHandler( epnum, transf ) )
- {
- // restore transfer
- usb_reset_transfer( transf );
- // error
- return USBD_FAIL;
- }
- }
- // retrieve amount of bytes to send
- uint16_t bytes_to_send = usb_count_transfer( transf );
- if( bytes_to_send > pep->maxpacket )
- {
- // limit the packet size to EP buffer size
- bytes_to_send = pep->maxpacket;
- // this is the last packet with size equal EP size: the next packet must be zero packet
- usb_transfer_set_shortpacket( transf );
- #if DEBUG_USB > 0
- gDebugUSBEPTxLastPacket = bytes_to_send;
- #endif
- }
- else
- {
- // detect if a zero packet must be send
- if( bytes_to_send == pep->maxpacket )
- {
- // this is the last packet with size equal EP size: the next packet must be zero packet
- usb_transfer_set_shortpacket( transf );
- }
- else if( bytes_to_send > 0 ) // bytes_to_send < pep->maxpacket
- {
- usb_transfer_clear_shortpacket( transf );
- }
- else
- // Check if there is no data to send:
- if( 0 == bytes_to_send )
- {
- // probably, the short packet shall be send, check it:
- if( ! usb_transfer_check_shortpacket( transf ) )
- {
- // no, there no Short Packet to be send
- // Thus, there no more data, exiting...
- return USBD_OK;
- }
- // yes, the short packet will be send now,
- // but it is requied to clear the indicator:
- usb_transfer_clear_shortpacket( transf );
- }
- }
- // send next data part:
- if( USBD_OK == USBD_EpContinueSendData( pdev, (uint8_t*)transf->pReadData, bytes_to_send, epnum ) )
- {
- #if DEBUG_USB > 0 // SCPI debug
- gDebugUSBEPTxBytes += bytes_to_send;
- #endif
- #if DEBUG_USB
- gDebugUSBEPTxLastPacket = bytes_to_send;
- #endif
- // perform virtual reading due to the USB Low Level have sent the data from the transfer
- usb_transfer_virtual_read( transf, bytes_to_send );
- return USBD_OK;
- }
- return USBD_FAIL;
- }
- // USBD_COMMON_DataOutProcess
- // Process DataOUT events for Bulk and Interrupt endpoints
- uint8_t USBD_COMMON_DataOutProcess( USBD_HandleTypeDef *pdev, uint8_t epnum, sUSBTransfer_t * transf, bool ShortPacketReceived )
- {
- USBD_EndpointTypeDef * pep = &pdev->ep_out[ epnum & 0x7F ];
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
- // Retrieve amount of received bytes:
- uint32_t nBytesReceived = pep->total_length - pep->rem_length;
- if( ShortPacketReceived )
- usb_transfer_set_shortpacket( transf ); // Data-out: short packet received
- else
- usb_transfer_clear_shortpacket( transf ); // Data-out: Not-short packet received
- if( NULL != pUserIface->fDataRxHandler )
- {
- // If zero packet received:
- if( 0 == nBytesReceived )
- {
- // restore transfer
- usb_reset_transfer( transf );
- if( pUserIface->fDataRxHandler( epnum, transf ) )
- {
- return USBD_OK;
- }
-
- goto DataOut_failed;
- }
- // Perform virtual writing to the transfer: the transfer had been modified in unusual way
- // check if the transfer able to receive such packet with length = @nBytesReceived
- if( ! usb_transfer_virtual_write( transf, nBytesReceived ) )
- {
- // No, error
- goto DataOut_failed;
- }
- #if 0
- // Check if transfer is not empty
- while( 0 < usb_count_transfer( transf ) )
- {
- #error User-defined handler @fDataRxHandler can defer the data processing til enough data is received for correct processing
- // Call user handler
- if( ! pUserIface->fDataRxHandler( epnum, transf ) )
- {
- // error: user handler call failed
- break;
- }
- }
- #else
- // Call user handler
- if( ! pUserIface->fDataRxHandler( epnum, transf ) )
- {
- goto DataOut_failed;
- }
- #endif
- #if 1
- // If a short packet received - it is a last transfer transaction
- if( ShortPacketReceived )
- {
- // this case no bytes can be deferred in the transfer due to no user handler
- // call is expected for this transfer after this transaction.
- if( 0 < usb_count_transfer( transf ) )
- {
- // if the transfer is not empty - this is error condition
- goto DataOut_failed;
- }
- // it is a last transfer transaction - prepare transfer for the first transaction (next transfer)
- usb_reset_transfer( transf );
- }
- #endif
- // retrieve amount of free bytes in the transfer
- uint16_t free_space = usb_space_transfer( transf );
-
- // Check if the transfer have enough free space for next transaction?
- if( usb_space_transfer( transf ) < pep->maxpacket )
- {
- // No, not enough free space
- goto DataOut_failed;
- }
- else
- {
- // yes, let's receive
- // Optimize the transfer buffer and compress the data
- usb_transfer_compress( transf );
- // To prepare the receiving next transfer, the transfer size must be a multiply of max_packet of endpoint
- free_space -= free_space % pep->maxpacket;
- }
- // prepare the transfer for the next OUT transaction
- return USBD_EpContinueRx( pdev, (uint8_t*)transf->pWriteData, free_space, epnum );
- }
- DataOut_failed:
- // restore transfer
- usb_reset_transfer( transf );
- return USBD_FAIL;
- }
- // USBD_COMMON_DataOutBegin
- // Prepare the EP for next OUT (receive) transaction
- uint8_t USBD_COMMON_DataOutBegin( USBD_HandleTypeDef *pdev, uint8_t epnum, sUSBTransfer_t * transf )
- {
- USBD_COMMON_ItfTypeDef * pUserIface = ((USBD_COMMON_ItfTypeDef *)pdev->pUserData);
- // if( NULL != pUserIface->fDataRxHandler )
- // {
- // // If the transfer contains a data
- // // Notify user about the data stored in the transfer
- // while( (0 < usb_count_transfer( transf )) && pUserIface->fDataRxHandler( epnum, transf ) )
- // {
- // // Optimize the transfer buffer and compress the data
- // usb_transfer_compress( transf );
- // }
- //
- // // Notify user about starting new transfer: transf=NULL
- // pUserIface->fDataRxHandler( epnum, NULL );
- // }
- // recover transfer
- usb_reset_transfer( transf );
- // retrieve amount of free bytes in the transfer
- uint16_t free_space = usb_space_transfer( transf );
- USBD_EndpointTypeDef * pep = &pdev->ep_out[ epnum & 0x7F ];
- // the transfer must be able to contain at least one full packet
- if( free_space >= pep->maxpacket )
- {
- // To prepare the receiving next transfer, the transfer size must be a multiply of max_packet of endpoint
- free_space -= free_space % pep->maxpacket;
- // prepare the transfer for the next OUT transaction
- return USBD_EpPrepareRx( pdev, (uint8_t *)transf->pWriteData, free_space, epnum );
- }
- (void)pUserIface;
- return USBD_FAIL;
- }
- /*
- // USBD_COMMON_DataOutBegin
- // Prepare the EP for next OUT (receive) transaction
- uint8_t USBD_COMMON_DataOutBegin( USBD_HandleTypeDef *pdev, uint8_t epnum, sUSBTransfer_t * transf )
- {
- // Optimize the transfer buffer and compress the data
- usb_transfer_compress( transf );
- // retrieve amount of free bytes in the transfer
- uint16_t free_space = usb_space_transfer( transf );
- // prepare the transfer for the next OUT transaction
- return USBD_EpPrepareRx( pdev, (uint8_t *)transf->pWriteData, free_space, epnum );
- }
- */
- /**
- * @brief USBD_COMMON_RegisterInterface
- * @param pdev: device instance
- * @param fops: CD Interface callback
- * @retval status
- */
- #if USBD_CONSTSUBCLASS_IFACE
- uint8_t USBD_COMMON_RegisterInterface (USBD_HandleTypeDef *pdev,
- const USBD_COMMON_ItfTypeDef *fops)
- #else
- uint8_t USBD_COMMON_RegisterInterface (USBD_HandleTypeDef *pdev,
- USBD_COMMON_ItfTypeDef *fops)
- #endif
- {
- uint8_t ret = USBD_FAIL;
-
- if(fops != NULL)
- {
- pdev->pUserData= fops;
- ret = USBD_OK;
- }
-
- return ret;
- }
|