// ----------------------------------------------------------------------------- // USB Library "usblib" // Author: Sychov A. // Date: 29/07/2019 // Version: 1.1 // ----------------------------------------------------------------------------- // File: Thread-unsafe internal buffer-object 'USB-transfer' header // Version: 1.1 // ------------------------------------------------------------------------------ #ifndef USB_LOGICAL_TRANSFER_H #define USB_LOGICAL_TRANSFER_H #include #include #include // USB_TRANSFER_MOVE_SEMANTIC // Enables a move semantic on the transfers. // When enabled, some functions will perfrom additional checking of a transfer parameters. #define USB_TRANSFER_MOVE_SEMANTIC 1 // USB_TRANSFER_SUPPORT_FLAGS // Implements user-defined flags support for each transfer #define USB_TRANSFER_SUPPORT_FLAGS 1 // USB_TRANSFER_SUPPORT_EOTH // Implements the End-of-transfer-handler support #define USB_TRANSFER_SUPPORT_EOTH 0 struct sUSBTransfer_t; // USB Transfers // Software module implements the logical data unit with separated // read- and write- methods based on linear buffer. // fEndOfTransferHandler_t // End-of-thansfer handler, is called when data in the transfer running out // @transf - the transfer generated the the handler call // @ctx - user defined context, the context specified at usb_create_pipe() // The handler is only called when usb_read_pipe() is performed. // The value returned by the handler must be amount of bytes loaded into the transfer typedef size_t ( * fEndOfTransferHandler_t)( struct sUSBTransfer_t * transf, void * ctx ); // @tUSBTransferFlag_t // User-dependent general-purpose bit flags typedef uint32_t tUSBTransferFlags_t; // @tUSBTransferFlagMask_t // User-dependent lock-mask for general-purpose bit flags typedef uint32_t tUSBTransferFlagMask_t; // @eUSBTransferFlagMode_t // Flags checking mode for @usb_transfer_check_flags() typedef enum { eUSBTransferFlagMode_Or, // OR-operation with mask eUSBTransferFlagMode_And, // AND-operation with mask } eUSBTransferFlagMode_t; // Usb Data Transfer Descriptor struct sUSBTransfer_t { size_t size; // maximum buffer capacity uint8_t * pDefaultBuffer; // Main data buffer uint8_t * pWriteData; // current Write-data pointer uint8_t * pReadData; // current Read-data pointer #if USB_TRANSFER_SUPPORT_EOTH // End-of-transfer handler: processes the event when the last byte of pipe transferred fEndOfTransferHandler_t fEndOfTransferHandler; #endif #if USB_TRANSFER_SUPPORT_FLAGS tUSBTransferFlags_t flags; tUSBTransferFlagMask_t flagsLock; #endif void * ctx; // used-defined context }; typedef struct sUSBTransfer_t sUSBTransfer_t; // USB Logical Pipe Descriptor typedef struct { sUSBTransfer_t TxTransfer; // IN: Device->Host pipe sUSBTransfer_t RxTransfer; // OUT: Host->Device pipe } sUSBEpChannel_t; // usb_reset_transfer() // Non thread-safe! // Resets the specified transfer. // Note: the specified end-of-transfer handler isn't called. void usb_reset_transfer( sUSBTransfer_t * pUsbTransfer ); // usb_reset_channel() // Non thread-safe! // Resets either RX and TX transfers in the channel void usb_reset_channel( sUSBEpChannel_t * ch ); // usb_reset_channel_tx() // Non thread-safe! // Resets the TX-transfer in the channel void usb_reset_channel_tx( sUSBEpChannel_t * ch ); // usb_reset_channel_rx() // Non thread-safe! // Resets the RX-transfer in the channel void usb_reset_channel_rx( sUSBEpChannel_t * ch ); #if USB_TRANSFER_SUPPORT_EOTH // usb_create_channel() // Creates a bidirectional linear-buffered logical-channel // @ch - the channel to construct // @pTxBuffer and @txSize - buffer and size of the buffer to Tx operations // @pRxBuffer and @rxSize - buffer and size of the buffer to Rx operations // @eotTxHandler - the event handler, is called when data run out in Tx Buffer // @eotRxHandler - the event handler, is called when data run out in Rx Buffer // @chContext - user defined context, will be passed into @eotTxHandler and @eotRxHandler // Returns true in case the channel is successfully created bool usb_create_channel( sUSBEpChannel_t * ch, void * pTxBuffer, size_t txSize, void * pRxBuffer, size_t rxSize, fEndOfTransferHandler_t eotTxHandler, fEndOfTransferHandler_t eotRxHandler, void * channelContext ); #else bool usb_create_channel( sUSBEpChannel_t * ch, void * pTxBuffer, size_t txSize, void * pRxBuffer, size_t rxSize, const void * reserved1, const void * reserved2, void * channelContext ); #endif // usb_create_transfer() // Creates a signle linear-buffered transfer // @transf - the transfer to construct // @pBuffer and @size - buffer and size of the buffer for transfer operations // @eotHandler - the event handler, is called when data run out in the buffer // @chContext - user defined context, will be passed into @eotHandler // Returns true in case the channel is successfully created #if USB_TRANSFER_SUPPORT_EOTH bool usb_create_transfer( sUSBTransfer_t * ch, void * pBuffer, size_t size, fEndOfTransferHandler_t eotHandler, void * channelContext ); #else bool usb_create_transfer( sUSBTransfer_t * ch, void * pBuffer, size_t size, const void * reserved, void * channelContext ); #endif // usb_push_transfer() // Non thread-safe! // Writes data into the transfer. // @transf - specifies the transfer to operate with // @pWriteBuffer - data to be written // @pushSize - amount of bytes to write // Returns the @pushSize in case all the data has been written into the transfer // Otherwise, returns 0. In this case no write operation has been performed. // Note: the write operation can be split up to several write operations, // until the buffer is full. // To prepare the transfer for next portion of data, use usb_reset_transfer() size_t usb_push_transfer( sUSBTransfer_t * transf, const void * pWriteBuffer, size_t pushSize ); // usb_write_transfer() // Non thread-safe! // Writes data into the transfer. // @transf - specifies the transfer to operate with // @pWriteBuffer - data to be written // @writeSize - amount of bytes to write // Returns amount of bytes written into the transfer // In this case no write operation has been performed the function returns 0. // Note: the write operation can be split up to several write operations, // until the buffer is full. // To prepare the transfer for next portion of data, use usb_reset_transfer() size_t usb_write_transfer( sUSBTransfer_t * transf, const void * pWriteBuffer, size_t writeSize ); // usb_read_transfer() // Non thread-safe! // Reads the data from the transfer. // @transf - specifies the transfer to operate with // @pReadBuffer - the buffer to receive data, can be NULL // @readSize - amount of data to copy into the @pReadBuffer, can be 0. // @enableEotHandler - enables/disables calling of End-Of-Transfer handler // during the call if the transfer is empty. // In case, @readSize is equal or greater than amount of data in the transfer, // the function reads actual amount of data and returns count of read bytes. // Since all data is read from the transfer, the transfer is being reset // automatically. If the End-of-transfer handler is specified for this transfer, // it will be invoked after the transfer is reset only if @enableEotHandler is // true, so the handler can write the next portion of data into the transfer. // Otherwise, if @readSize is less than amount of data in the transfer, then // only @readSize bytes will be copyied into @pReadBuffer, the rest data are // still stored in the transfer-buffer and should be either read by next call, // or reset by calling usb_reset_transfer(). // Note: if the data in transfer is reset by calling usb_reset_transfer(), the // End-of-pipe handler is not called. // You can call the function with @pReadBuffer = NULL and @readSize = 0, and // @enableEotHandler = true to check if the transfer empty and call the End-of- // -transfer handler. In this case the function always returns zero. // Note: if you specify @pReadBuffer = NULL, you must set @readSize = 0. // To determine amount of bytes in the transfer use usb_count_transfer(). // size_t usb_read_transfer( sUSBTransfer_t * transf, void * pReadBuffer, size_t readSize, bool enableEotHandler ); // usb_count_transfer(): // Non thread-safe! // Returns amount of data in the transfer. // @transf - the transfer to operate with, Non-NULL // Returns amount of data to be read. size_t usb_count_transfer( sUSBTransfer_t * transf ); // usb_truncate_transfer() // // Non thread-safe! // // Truncates the data into the transfer. // @transf - the transfer to operate with, Non-NULL // @size - the size limit to apply // The function truncates the data in the transfer to the specified @size // Returns amount of data truncated. size_t usb_truncate_transfer( sUSBTransfer_t * transf, size_t size ); #if USB_TRANSFER_SUPPORT_EOTH // usb_transfer_override_handler: // Replaces the End-of-transfer handler for the specified transfer @transf // @transf - the transfer to operate with // @handler - new end-of-transfer handler // If succeeded, the previous handler pointer is returned by function, and NULL otherwise. fEndOfTransferHandler_t usb_transfer_override_handler( sUSBTransfer_t * transf, fEndOfTransferHandler_t handler ); #endif // usb_transfer_overridelength() // // Non thread-safe! // // Overrides the transfer data length. // @transf - the transfer to operate with, Non-NULL // @length - new length // The function overrides the original transfer data length with the specified @length // Returns new length value. size_t usb_transfer_overridelength( sUSBTransfer_t * transf, size_t length ); // usb_transfer_virtual_read() // // Non thread-safe! // // Performs virtual reading from transfer without actual data retrieving from. // @transf - the transfer to operate with, Non-NULL // @length - the number of bytes for virtual reading // The function changes the transfer data length. // Returns the number of read bytes size_t usb_transfer_virtual_read( sUSBTransfer_t * transf, size_t length ); // usb_transfer_virtual_write() // // Non thread-safe! // // Performs virtual writing to transfer without actual data placing in. // @transf - the transfer to operate with, Non-NULL // @length - the number of bytes for virtual writing // The function changes the transfer data length. // Returns the number of written bytes size_t usb_transfer_virtual_write( sUSBTransfer_t * transf, size_t length ); // usb_transfer_compress() // // Non thread-safe! // // Optimizes the transfer by size by packing data inside. // @transf - the transfer to operate with, Non-NULL // The function moves the data from middle of the transfer to the beginning // with keeping actual size. // Returns new length value. size_t usb_transfer_compress( sUSBTransfer_t * transf ); // usb_size_transfer() // // Non thread-safe! // // Returns the transfer absoulte size. // @transf - the transfer to operate with, Non-NULL // Returns the size in bytes size_t usb_size_transfer( sUSBTransfer_t * transf ); // usb_space_transfer() // // Non thread-safe! // // Returns the transfer available space. // @transf - the transfer to operate with, Non-NULL // Returns amount of free space in the transfer in bytes. size_t usb_space_transfer( sUSBTransfer_t * transf ); // usb_transfer_raw_write() // Returns raw write-pointer to the transfer storage. // # Ponetially dangerous function, use usb_space_transfer() before. static inline void * usb_transfer_raw_write( sUSBTransfer_t * transf ) { return transf->pWriteData; } // usb_transfer_raw_read() // Returns raw read-pointer to the transfer storage. // # Ponetially dangerous function, use usb_count_transfer() before. static inline void * usb_transfer_raw_read( sUSBTransfer_t * transf ) { return transf->pReadData; } #if USB_TRANSFER_MOVE_SEMANTIC // usb_move_transfer() // // Non thread-safe! // // Implements a move-semantic on couple of transfer objects // @transf_to - the transfer for move to, can not be NULL // @transf_from - the transfer for move from, can not be NULL // @copyContextValue - copy the context value assotiated with the source tranfer. // Returns the operation result, true if object had been moved // successfully, and false otherwise. // The source object (@transf_from) must be valid, while it does // not matter if the destination object @transf_to is invalid or not. bool usb_move_transfer( sUSBTransfer_t * transf_to, sUSBTransfer_t * transf_from, bool copyContextValue ); #endif // usb_validate_transfer() // // Non thread-safe! // // Validates the transfer parameters. Usefull for checking objects // after moving by usb_move_transfer(). // @transf - the transfer to operate with, Non-NULL // Returns true if the specified object is valid, false otherwise. bool usb_validate_transfer( sUSBTransfer_t * transf ); // usb_transfer_get_context // // Non thread-safe! // // Retrieves optional user context value. // @transf - the transfer to operate with, Non-NULL // @pCtxStore - the pointer to the variable the function will store // the context value to, must not be NULL // // Returns the context value assotiated with the @transf // In case of success returns 'true', and returns 'false' otherwise. static inline bool usb_transfer_get_context( sUSBTransfer_t * transf, void ** pCtxStore ) { if( NULL != transf && NULL != pCtxStore ) { *pCtxStore = transf->ctx; return true; } return false; } // usb_transfer_set_context // // Non thread-safe! // // Assotiate optional user context value with the transfer. // @transf - the transfer to operate with, Non-NULL // @pCtx - user-dependent context value to be assotiated with the transfer, can be NULL // // Returns the context value assotiated with the @transf // In case of success returns 'true', and returns 'false' otherwise. static inline bool usb_transfer_set_context( sUSBTransfer_t * transf, void * pCtx ) { if( NULL != transf ) { transf->ctx = pCtx; return true; } return false; } // usb_copy_transfer() // Copies the data from one transfer to another // The source transfer is not being modified if @keepSource is true. // Otherwise, if @keepSource is false, the source transfer will be changed, // and the data copied to destination transfer will be removed from the source transfer. // @count - specifies amount of data to be copied. // If the source transfer contains less bytes that specified in @count, or the // destination transfer does not have enough free space, only the minimum between // these number of bytes will be copied. // Returns: number of copied bytes size_t usb_copy_transfer( sUSBTransfer_t * transf_to, sUSBTransfer_t * transf_from, size_t count, bool keepSource ); #if USB_TRANSFER_SUPPORT_FLAGS // @usb_transfer_check_flags // Check if the user-dependent general-purpose flags fit to the specified mask @mask and value @value using comparing method @mode. // @transf - the transfer object to operate with; // @mask - specified mask to check // @value - specified value to check // @mode - comparing method: // - eUSBTransferFlagMode_Or: at least one transfer bit-flag must be equal to the specified value; // - eUSBTransferFlagMode_And: all the transfer bit-flag must be equal to the specified value; // @pResult = the pointer to receive output result // Returns: true if no error occurred, false otherwise. bool usb_transfer_check_flags( sUSBTransfer_t * transf, tUSBTransferFlags_t mask, tUSBTransferFlags_t value, eUSBTransferFlagMode_t mode, bool * pResult ); // @usb_transfer_check_flags_fast // Check if the user-dependent general-purpose flags fit to the specified mask @mask and value @value using comparing method @mode. // @transf - the transfer object to operate with; // @mask - specified mask to check // @value - specified value to check // @mode - comparing method: // - eUSBTransferFlagMode_Or: at least one transfer bit-flag must be equal to the specified value; // - eUSBTransferFlagMode_And: all the transfer bit-flag must be equal to the specified value; // Returns: true if no error occurred and the comparing output is TRUE, false otherwise. // Note: you can use this function instead of @usb_transfer_check_flags if you are sure that the @transf pointer is valid. bool usb_transfer_check_flags_fast( sUSBTransfer_t * transf, tUSBTransferFlags_t mask, tUSBTransferFlags_t value, eUSBTransferFlagMode_t mode ); // @usb_transfer_modify_flags // Modifies the user-dependent general-purpose flags using specified mask @mask and value @value // Returns: true if no error occurred, false otherwise. bool usb_transfer_modify_flags( sUSBTransfer_t * transf, tUSBTransferFlags_t mask, tUSBTransferFlags_t value ); // @usb_transfer_modify_flags_locks // Modifies the lock mask for user-dependent general-purpose flags using specified mask @mask and value @value // Returns: true if no error occurred, false otherwise. bool usb_transfer_modify_flags_locks( sUSBTransfer_t * transf, tUSBTransferFlags_t lockMask, tUSBTransferFlags_t lockValue ); #endif #endif