usb_transfers.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. // -----------------------------------------------------------------------------
  2. // USB Library "usblib"
  3. // Author: Sychov A.
  4. // Date: 29/07/2019
  5. // Version: 1.1
  6. // -----------------------------------------------------------------------------
  7. // File: Thread-unsafe internal buffer-object 'USB-transfer'
  8. // Version: 1.1
  9. // -----------------------------------------------------------------------------
  10. #define __USER_USB_HEADER__
  11. #include <string.h>
  12. #include "usb/usb_transfers.h"
  13. //----------------------------------------------------------------------------
  14. // usb_reset_transfer()
  15. //
  16. // Non thread-safe!
  17. //
  18. // Resets the specified transfer.
  19. // Note: the specified end-of-transfer handler isn't called.
  20. void usb_reset_transfer( sUSBTransfer_t * pUsbTransfer )
  21. {
  22. if( NULL != pUsbTransfer )
  23. {
  24. pUsbTransfer->pWriteData = pUsbTransfer->pDefaultBuffer;
  25. pUsbTransfer->pReadData = pUsbTransfer->pDefaultBuffer;
  26. #if USB_TRANSFER_SUPPORT_FLAGS
  27. // reset only unlocked flags
  28. pUsbTransfer->flags = pUsbTransfer->flags & (pUsbTransfer->flagsLock);
  29. #endif
  30. }
  31. }
  32. //----------------------------------------------------------------------------
  33. // usb_reset_channel()
  34. //
  35. // Non thread-safe!
  36. //
  37. // Resets either RX and TX transfers in the channel
  38. void usb_reset_channel( sUSBEpChannel_t * ch )
  39. {
  40. usb_reset_transfer( &ch->RxTransfer );
  41. usb_reset_transfer( &ch->TxTransfer );
  42. }
  43. //----------------------------------------------------------------------------
  44. // usb_reset_channel_tx()
  45. //
  46. // Non thread-safe!
  47. //
  48. // Resets the TX-transfer in the channel
  49. void usb_reset_channel_tx( sUSBEpChannel_t * ch )
  50. {
  51. usb_reset_transfer( &ch->TxTransfer );
  52. }
  53. //----------------------------------------------------------------------------
  54. // usb_reset_channel_rx()
  55. //
  56. // Non thread-safe!
  57. //
  58. // Resets the RX-transfer in the channel
  59. void usb_reset_channel_rx( sUSBEpChannel_t * ch )
  60. {
  61. usb_reset_transfer( &ch->RxTransfer );
  62. }
  63. //----------------------------------------------------------------------------
  64. // usb_create_channel()
  65. // Creates a bidirectional linear-buffered logical-channel
  66. // @ch - the channel to construct
  67. // @pTxBuffer and @txSize - buffer and size of the buffer to Tx operations
  68. // @pRxBuffer and @rxSize - buffer and size of the buffer to Rx operations
  69. // @eotTxHandler - the event handler, is called when data run out in Tx Buffer
  70. // @eotRxHandler - the event handler, is called when data run out in Rx Buffer
  71. // @chContext - user defined context, will be passed into @eotTxHandler and @eotRxHandler
  72. // Returns true in case the channel is successfully created
  73. #if USB_TRANSFER_SUPPORT_EOTH
  74. bool usb_create_channel( sUSBEpChannel_t * ch,
  75. void * pTxBuffer, size_t txSize,
  76. void * pRxBuffer, size_t rxSize,
  77. fEndOfTransferHandler_t eotTxHandler,
  78. fEndOfTransferHandler_t eotRxHandler,
  79. void * channelContext )
  80. #else
  81. bool usb_create_channel( sUSBEpChannel_t * ch,
  82. void * pTxBuffer, size_t txSize,
  83. void * pRxBuffer, size_t rxSize,
  84. const void * reserved1,
  85. const void * reserved2,
  86. void * channelContext )
  87. #endif
  88. {
  89. #if USB_TRANSFER_SUPPORT_EOTH
  90. return
  91. usb_create_transfer( &ch->RxTransfer, pRxBuffer, rxSize, eotRxHandler, channelContext )
  92. && usb_create_transfer( &ch->TxTransfer, pTxBuffer, txSize, eotTxHandler, channelContext );
  93. #else
  94. return
  95. usb_create_transfer( &ch->RxTransfer, pRxBuffer, rxSize, reserved1, channelContext )
  96. && usb_create_transfer( &ch->TxTransfer, pTxBuffer, txSize, reserved2, channelContext );
  97. #endif
  98. /*
  99. if( NULL == pTxBuffer || NULL == pRxBuffer ||
  100. 0 == txSize || 0 == rxSize )
  101. {
  102. return false;
  103. }
  104. ch->RxTransfer.pDefaultBuffer = (uint8_t*)pTxBuffer;
  105. ch->RxTransfer.size = txSize;
  106. ch->RxTransfer.fEndOfTransferHandler = eotRxHandler;
  107. ch->RxTransfer.ctx = channelContext;
  108. ch->TxTransfer.pDefaultBuffer = (uint8_t*)pRxBuffer;
  109. ch->TxTransfer.size = rxSize;
  110. ch->TxTransfer.fEndOfTransferHandler = eotTxHandler;
  111. ch->TxTransfer.ctx = channelContext;
  112. usb_reset_channel( ch );
  113. return true;
  114. */
  115. }
  116. //----------------------------------------------------------------------------
  117. // usb_create_transfer()
  118. // Creates a signle linear-buffered transfer
  119. // @transf - the transfer to construct
  120. // @pBuffer and @size - buffer and size of the buffer for transfer operations
  121. // @eotHandler - the event handler, is called when data run out in the buffer
  122. // @chContext - user defined context, will be passed into @eotHandler
  123. // Returns true in case the channel is successfully created
  124. #if USB_TRANSFER_SUPPORT_EOTH
  125. bool usb_create_transfer( sUSBTransfer_t * transf,
  126. void * pBuffer, size_t size,
  127. fEndOfTransferHandler_t eotHandler,
  128. void * channelContext )
  129. #else
  130. bool usb_create_transfer( sUSBTransfer_t * transf,
  131. void * pBuffer, size_t size,
  132. const void * reserved,
  133. void * channelContext )
  134. #endif
  135. {
  136. if( NULL == pBuffer || 0 == size )
  137. {
  138. return false;
  139. }
  140. transf->pDefaultBuffer = (uint8_t*)pBuffer;
  141. transf->size = size;
  142. #if USB_TRANSFER_SUPPORT_EOTH
  143. transf->fEndOfTransferHandler = eotHandler;
  144. #endif
  145. transf->ctx = channelContext;
  146. #if USB_TRANSFER_SUPPORT_FLAGS
  147. transf->flags = 0;
  148. transf->flagsLock = 0; // no lock by default
  149. #endif
  150. usb_reset_transfer( transf );
  151. return true;
  152. }
  153. // usb_push_transfer()
  154. // Non thread-safe!
  155. // Writes data into the transfer.
  156. // @transf - specifies the transfer to operate with
  157. // @pWriteBuffer - data to be written
  158. // @pushSize - amount of bytes to write
  159. // Returns the @pushSize in case all the data has been written into the transfer
  160. // Otherwise, returns 0. In this case no write operation has been performed.
  161. // Note: the write operation can be split up to several write operations,
  162. // until the buffer is full.
  163. // To prepare the transfer for next portion of data, use usb_reset_transfer()
  164. size_t usb_push_transfer( sUSBTransfer_t * transf, const void * pWriteBuffer, size_t pushSize )
  165. {
  166. #if USB_TRANSFER_MOVE_SEMANTIC
  167. if( NULL != transf && NULL != pWriteBuffer && 0 != pushSize && NULL != transf->pDefaultBuffer && 0 != transf->size )
  168. #else
  169. if( NULL != transf && NULL != pWriteBuffer && 0 != pushSize )
  170. #endif
  171. {
  172. size_t length = ((ptrdiff_t)transf->pWriteData - (ptrdiff_t)transf->pDefaultBuffer);
  173. if( length + pushSize <= transf->size )
  174. {
  175. memcpy( transf->pWriteData, pWriteBuffer, pushSize );
  176. transf->pWriteData += pushSize;
  177. return pushSize;
  178. }
  179. }
  180. return 0;
  181. }
  182. // usb_write_transfer()
  183. // Non thread-safe!
  184. // Writes data into the transfer.
  185. // @transf - specifies the transfer to operate with
  186. // @pWriteBuffer - data to be written
  187. // @writeSize - amount of bytes to write
  188. // Returns amount of bytes written into the transfer
  189. // In this case no write operation has been performed the function returns 0.
  190. // Note: the write operation can be split up to several write operations,
  191. // until the buffer is full.
  192. // To prepare the transfer for next portion of data, use usb_reset_transfer()
  193. size_t usb_write_transfer( sUSBTransfer_t * transf, const void * pWriteBuffer, size_t writeSize )
  194. {
  195. #if USB_TRANSFER_MOVE_SEMANTIC
  196. if( NULL != transf && NULL != pWriteBuffer && 0 != writeSize && NULL != transf->pDefaultBuffer && 0 != transf->size )
  197. #else
  198. if( NULL != transf && NULL != pWriteBuffer && 0 != writeSize )
  199. #endif
  200. {
  201. size_t length = ((ptrdiff_t)transf->pWriteData - (ptrdiff_t)transf->pDefaultBuffer);
  202. if( length + writeSize > transf->size )
  203. {
  204. writeSize = transf->size - length;
  205. }
  206. if( writeSize )
  207. {
  208. memcpy( transf->pWriteData, pWriteBuffer, writeSize );
  209. transf->pWriteData += writeSize;
  210. return writeSize;
  211. }
  212. }
  213. return 0;
  214. }
  215. // usb_read_transfer()
  216. //
  217. // Non thread-safe!
  218. //
  219. // Reads the data from the transfer.
  220. // @transf - specifies the transfer to operate with
  221. // @pReadBuffer - the buffer to receive data, can be NULL
  222. // @readSize - amount of data to copy into the @pReadBuffer, can be 0.
  223. // @enableEotHandler - enables/disables calling of End-Of-Transfer handler
  224. // during the call if the transfer is empty.
  225. // In case, @readSize is equal or greater than amount of data in the transfer,
  226. // the function reads actual amount of data and returns count of read bytes.
  227. // Since all data is read from the transfer, the transfer is being reset
  228. // automatically. If the End-of-transfer handler is specified for this transfer,
  229. // it will be invoked after the transfer is reset only if @enableEotHandler is
  230. // true, so the handler can write the next portion of data into the transfer.
  231. // Otherwise, if @readSize is less than amount of data in the transfer, then
  232. // only @readSize bytes will be copyied into @pReadBuffer, the rest data are
  233. // still stored in the transfer-buffer and should be either read by next call,
  234. // or reset by calling usb_reset_transfer().
  235. // Note: if the data in transfer is reset by calling usb_reset_transfer(), the
  236. // End-of-pipe handler is not called.
  237. // You can call the function with @pReadBuffer = NULL and @readSize = 0, and
  238. // @enableEotHandler = true to check if the transfer empty and call the End-of-
  239. // -transfer handler. In this case the function always returns zero.
  240. // Note: if you specify @pReadBuffer = NULL, you must set @readSize = 0.
  241. // To determine amount of bytes in the transfer use usb_count_transfer().
  242. //
  243. size_t usb_read_transfer( sUSBTransfer_t * transf, void * pReadBuffer, size_t readSize, bool enableEotHandler )
  244. {
  245. #if USB_TRANSFER_MOVE_SEMANTIC
  246. if( NULL != transf && NULL != transf->pDefaultBuffer && 0 != transf->size )
  247. #else
  248. if( NULL != transf )
  249. #endif
  250. {
  251. // retireve the data length in transfer
  252. size_t length = (ptrdiff_t)transf->pWriteData - (ptrdiff_t)transf->pReadData;
  253. // check user params:
  254. if( NULL != pReadBuffer && 0 != readSize )
  255. {
  256. // for the length greater than 0:
  257. if( length > 0 )
  258. {
  259. // user requests the part of all the data:
  260. if( readSize < length )
  261. {
  262. memcpy( pReadBuffer, transf->pReadData, readSize );
  263. transf->pReadData += readSize;
  264. return readSize;
  265. }
  266. // user request all the data:
  267. else
  268. {
  269. memcpy( pReadBuffer, transf->pReadData, length );
  270. // reset transfer
  271. transf->pReadData = transf->pDefaultBuffer;
  272. transf->pWriteData = transf->pDefaultBuffer;
  273. // call the handler if allowed and specified:
  274. #if USB_TRANSFER_SUPPORT_EOTH
  275. if( enableEotHandler )
  276. if( NULL != transf->fEndOfTransferHandler )
  277. {
  278. size_t rc = transf->fEndOfTransferHandler( transf, transf->ctx );
  279. (void)rc;
  280. }
  281. #endif
  282. return length;
  283. }
  284. }
  285. }
  286. else
  287. {
  288. // user want to check if the transfer empty and call the handler:
  289. #if USB_TRANSFER_SUPPORT_EOTH
  290. // check the length
  291. if( (length == 0)
  292. &&
  293. enableEotHandler
  294. &&
  295. (NULL != transf->fEndOfTransferHandler)
  296. )
  297. {
  298. // call the handler
  299. size_t rc = transf->fEndOfTransferHandler( transf, transf->ctx );
  300. (void)rc;
  301. }
  302. #endif
  303. return 0; // by design, see description
  304. }
  305. }
  306. return 0;
  307. }
  308. // usb_count_transfer():
  309. //
  310. // Non thread-safe!
  311. //
  312. // Returns amount of data in the transfer.
  313. // @transf - the transfer to operate with, Non-NULL
  314. // Returns amount of data to be read.
  315. size_t usb_count_transfer( sUSBTransfer_t * transf )
  316. {
  317. #if USB_TRANSFER_MOVE_SEMANTIC
  318. if( NULL != transf && NULL != transf->pDefaultBuffer && 0 != transf->size )
  319. #else
  320. if( NULL != transf )
  321. #endif
  322. {
  323. // retireve the data length in transfer
  324. size_t length = (ptrdiff_t)transf->pWriteData - (ptrdiff_t)transf->pReadData;
  325. return length;
  326. }
  327. return 0;
  328. }
  329. // usb_truncate_transfer()
  330. //
  331. // Non thread-safe!
  332. //
  333. // Truncates the data into the transfer.
  334. // @transf - the transfer to operate with, Non-NULL
  335. // @size - the size limit to apply
  336. // The function truncates the data in the transfer to the specified @size
  337. // Returns acutal amount of data in the transfer.
  338. size_t usb_truncate_transfer( sUSBTransfer_t * transf, size_t size )
  339. {
  340. #if USB_TRANSFER_MOVE_SEMANTIC
  341. if( NULL != transf && NULL != transf->pDefaultBuffer && 0 != transf->size )
  342. #else
  343. if( NULL != transf )
  344. #endif
  345. {
  346. // retireve the data length in transfer
  347. size_t length = (ptrdiff_t)transf->pWriteData - (ptrdiff_t)transf->pReadData;
  348. // truncate only if the transfer contains more data than specified by @size
  349. if( length > size )
  350. {
  351. // cut off extra data
  352. transf->pWriteData = (uint8_t*)((ptrdiff_t)transf->pReadData + (ptrdiff_t)size);
  353. // return amount of cut bytes
  354. return (size);
  355. }
  356. return (length);
  357. }
  358. return 0;
  359. }
  360. #if USB_TRANSFER_SUPPORT_EOTH
  361. // usb_transfer_override_handler:
  362. // Replaces the End-of-transfer handler for the specified transfer @transf
  363. // @transf - the transfer to operate with
  364. // @handler - new end-of-transfer handler
  365. // If succeeded, the previous handler pointer is returned by function, and NULL otherwise.
  366. fEndOfTransferHandler_t usb_transfer_override_handler( sUSBTransfer_t * transf, fEndOfTransferHandler_t handler )
  367. {
  368. if( NULL != transf )
  369. {
  370. fEndOfTransferHandler_t prevHandler = transf->fEndOfTransferHandler;
  371. transf->fEndOfTransferHandler = handler;
  372. return prevHandler;
  373. }
  374. return NULL;
  375. }
  376. #endif
  377. // usb_transfer_overridelength()
  378. //
  379. // Non thread-safe!
  380. //
  381. // Overrides the transfer data length.
  382. // @transf - the transfer to operate with, Non-NULL
  383. // @length - new length
  384. // The function overrides the original transfer data length with the specified @length
  385. // Returns new length value.
  386. size_t usb_transfer_overridelength( sUSBTransfer_t * transf, size_t length )
  387. {
  388. #if USB_TRANSFER_MOVE_SEMANTIC
  389. if( NULL != transf && NULL != transf->pDefaultBuffer && 0 != transf->size )
  390. #else
  391. if( NULL != transf )
  392. #endif
  393. {
  394. if( length > transf->size )
  395. {
  396. length = transf->size;
  397. }
  398. // set the length
  399. transf->pWriteData = (uint8_t*)((ptrdiff_t)transf->pDefaultBuffer + (ptrdiff_t)length);
  400. return (length);
  401. }
  402. return 0;
  403. }
  404. // usb_transfer_virtual_read()
  405. //
  406. // Non thread-safe!
  407. //
  408. // Performs virtual reading from transfer without actual data retrieving from.
  409. // @transf - the transfer to operate with, Non-NULL
  410. // @length - the number of bytes for virtual reading
  411. // The function changes the transfer data length.
  412. // Returns the number of read bytes
  413. size_t usb_transfer_virtual_read( sUSBTransfer_t * transf, size_t length )
  414. {
  415. #if USB_TRANSFER_MOVE_SEMANTIC
  416. if( (NULL != transf) && (length > 0) && NULL != transf->pDefaultBuffer && 0 != transf->size )
  417. #else
  418. if( (NULL != transf) && (length > 0) )
  419. #endif
  420. {
  421. // retireve the data length in transfer
  422. size_t stored_length = (ptrdiff_t)transf->pWriteData - (ptrdiff_t)transf->pReadData;
  423. if( length > stored_length )
  424. {
  425. length = stored_length;
  426. }
  427. // perform virtual reading by shifting the pointer @pReadData
  428. transf->pReadData = (uint8_t*)((ptrdiff_t)transf->pReadData + (ptrdiff_t)length);
  429. return (length);
  430. }
  431. return 0;
  432. }
  433. // usb_transfer_virtual_write()
  434. //
  435. // Non thread-safe!
  436. //
  437. // Performs virtual writing to transfer without actual data placing in.
  438. // @transf - the transfer to operate with, Non-NULL
  439. // @length - the number of bytes for virtual writing
  440. // The function changes the transfer data length.
  441. // Returns the number of written bytes
  442. size_t usb_transfer_virtual_write( sUSBTransfer_t * transf, size_t length )
  443. {
  444. #if USB_TRANSFER_MOVE_SEMANTIC
  445. if( (NULL != transf) && (length > 0) && NULL != transf->pDefaultBuffer && 0 != transf->size )
  446. #else
  447. if( (NULL != transf) && (length > 0) )
  448. #endif
  449. {
  450. // retireve the remaining length in transfer
  451. size_t remaining_length = transf->size - ((ptrdiff_t)transf->pWriteData - (ptrdiff_t)transf->pDefaultBuffer);
  452. if( length > remaining_length )
  453. {
  454. length = remaining_length;
  455. }
  456. // perform writing reading by shifting the pointer @pWriteData
  457. transf->pWriteData = (uint8_t*)((ptrdiff_t)transf->pWriteData + (ptrdiff_t)length);
  458. return (length);
  459. }
  460. return 0;
  461. }
  462. // usb_transfer_compress()
  463. //
  464. // Non thread-safe!
  465. //
  466. // Optimizes the transfer by size by packing data inside.
  467. // @transf - the transfer to operate with, Non-NULL
  468. // The function moves the data from middle of the transfer to the beginning
  469. // with keeping actual size.
  470. // Returns the number of bytes optimized
  471. size_t usb_transfer_compress( sUSBTransfer_t * transf )
  472. {
  473. #if USB_TRANSFER_MOVE_SEMANTIC
  474. if( NULL != transf && NULL != transf->pDefaultBuffer && 0 != transf->size )
  475. #else
  476. if( NULL != transf )
  477. #endif
  478. {
  479. // retireve the data length in transfer
  480. size_t stored_length = (ptrdiff_t)transf->pWriteData - (ptrdiff_t)transf->pReadData;
  481. if( stored_length > 0 )
  482. {
  483. // move the contents by to the beginning of the transfer (re-use)
  484. memmove( transf->pDefaultBuffer, transf->pReadData, stored_length );
  485. transf->pWriteData = (uint8_t*)((ptrdiff_t)transf->pDefaultBuffer + stored_length);
  486. }
  487. else
  488. {
  489. transf->pWriteData = transf->pDefaultBuffer;
  490. }
  491. size_t optimized_length = (ptrdiff_t)transf->pReadData - (ptrdiff_t)transf->pDefaultBuffer;
  492. transf->pReadData = transf->pDefaultBuffer;
  493. return optimized_length;
  494. }
  495. return 0;
  496. }
  497. // usb_size_transfer()
  498. //
  499. // Non thread-safe!
  500. //
  501. // Returns the transfer absoulte size.
  502. // @transf - the transfer to operate with, Non-NULL
  503. // Returns the size in bytes
  504. size_t usb_size_transfer( sUSBTransfer_t * transf )
  505. {
  506. #if USB_TRANSFER_MOVE_SEMANTIC
  507. if( NULL != transf && NULL != transf->pDefaultBuffer && 0 != transf->size )
  508. #else
  509. if( NULL != transf )
  510. #endif
  511. {
  512. return (transf->size);
  513. }
  514. return 0;
  515. }
  516. // usb_space_transfer()
  517. //
  518. // Non thread-safe!
  519. //
  520. // Returns the transfer available space.
  521. // @transf - the transfer to operate with, Non-NULL
  522. // Returns amount of free space in the transfer in bytes.
  523. size_t usb_space_transfer( sUSBTransfer_t * transf )
  524. {
  525. #if USB_TRANSFER_MOVE_SEMANTIC
  526. if( NULL != transf && NULL != transf->pDefaultBuffer && 0 != transf->size )
  527. #else
  528. if( NULL != transf )
  529. #endif
  530. {
  531. // retireve the data length in transfer
  532. size_t used_length = (ptrdiff_t)transf->pWriteData - (ptrdiff_t)transf->pDefaultBuffer;
  533. return (transf->size - used_length);
  534. }
  535. return 0;
  536. }
  537. #if USB_TRANSFER_MOVE_SEMANTIC
  538. // usb_move_transfer()
  539. //
  540. // Non thread-safe!
  541. //
  542. // Implements a move-semantic on couple of transfer objects
  543. // @transf_to - the transfer for move to, can not be NULL
  544. // @transf_from - the transfer for move from, can not be NULL
  545. // @copyContextValue - copy the context value assotiated with the source tranfer.
  546. // The source object (@transf_from) must be valid, while it does
  547. // not matter if the destination object @transf_to is invalid or not.
  548. // After operation the source object will be destroyed, you must
  549. // call usb_move_transfer() or usb_create_transfer() function on the source
  550. // transfer to recover it.
  551. // Note: user context in the source transfer will not be cleared and it can
  552. // be used after the function call.
  553. // Returns the operation result, true if object had been moved
  554. // successfully, and false otherwise.
  555. bool usb_move_transfer( sUSBTransfer_t * transf_to, sUSBTransfer_t * transf_from, bool copyContextValue )
  556. {
  557. if( NULL != transf_to && NULL != transf_from && NULL != transf_from->pDefaultBuffer && 0 != transf_from->size )
  558. {
  559. void * pDestUserContext = transf_to->ctx;
  560. *transf_to = *transf_from;
  561. transf_from->pDefaultBuffer = NULL;
  562. transf_from->pWriteData = NULL;
  563. transf_from->pReadData = NULL;
  564. transf_from->size = 0;
  565. #if USB_TRANSFER_SUPPORT_FLAGS
  566. // reset only the bits that are reset in @flagsLock
  567. // If the bit is set in @flagsLock, the corresponding bit will be kept in @flags
  568. transf_from->flags = transf_from->flags & transf_from->flagsLock;
  569. #endif
  570. #if USB_TRANSFER_SUPPORT_EOTH
  571. transf_from->fEndOfTransferHandler = NULL;
  572. #endif
  573. if( !copyContextValue )
  574. {
  575. transf_to->ctx = pDestUserContext;
  576. }
  577. // keep the source transfer's context unchanged
  578. (void)transf_from->ctx;
  579. }
  580. return false;
  581. }
  582. // usb_copy_transfer()
  583. // Copies the data from one transfer to another
  584. // The source transfer is not being modified if @keepSource is true.
  585. // Otherwise, if @keepSource is false, the source transfer will be changed,
  586. // and the data copied to destination transfer will be removed from the source transfer.
  587. // @count - specifies amount of data to be copied.
  588. // If the source transfer contains less bytes that specified in @count, or the
  589. // destination transfer does not have enough free space, only the minimum between
  590. // these number of bytes will be copied.
  591. // Returns: number of copied bytes
  592. size_t usb_copy_transfer( sUSBTransfer_t * transf_to, sUSBTransfer_t * transf_from, size_t count, bool keepSource )
  593. {
  594. if( NULL == transf_to || NULL == transf_from || 0 == count )
  595. {
  596. return 0;
  597. }
  598. #if USB_TRANSFER_MOVE_SEMANTIC
  599. if( NULL == transf_to->pDefaultBuffer || 0 == transf_to->size
  600. || NULL == transf_from->pDefaultBuffer || 0 == transf_from->size )
  601. {
  602. return 0;
  603. }
  604. #endif
  605. // retireve free space from the destination transfer
  606. size_t free_space = transf_to->size - ((ptrdiff_t)transf_to->pWriteData - (ptrdiff_t)transf_to->pDefaultBuffer);
  607. // retrieve used length from the source transfer
  608. size_t used_space = (ptrdiff_t)transf_from->pWriteData - (ptrdiff_t)transf_from->pDefaultBuffer;
  609. // check the limits: count must be less or equal to MIN( used_space, free_space )
  610. if( count > free_space ) count = free_space;
  611. if( count > used_space ) count = used_space;
  612. memcpy( transf_to->pWriteData, transf_from->pReadData, count );
  613. // perform virtual writing by shifting the pointer @pWriteData
  614. transf_to->pWriteData = (uint8_t*)((ptrdiff_t)transf_to->pWriteData + (ptrdiff_t)count);
  615. if( !keepSource )
  616. {
  617. // perform virtual reading by shifting the pointer @pReadData
  618. transf_from->pReadData = (uint8_t*)((ptrdiff_t)transf_from->pReadData + (ptrdiff_t)count);
  619. }
  620. return count;
  621. }
  622. // usb_validate_transfer()
  623. //
  624. // Non thread-safe!
  625. //
  626. // Validates the transfer parameters. Usefull for checking objects
  627. // after moving by usb_move_transfer().
  628. // @transf - the transfer to operate with, Non-NULL
  629. // Returns true if the specified object is valid, false otherwise.
  630. bool usb_validate_transfer( sUSBTransfer_t * transf )
  631. {
  632. if( NULL != transf && NULL != transf->pDefaultBuffer && 0 != transf->size )
  633. if( NULL != transf->pWriteData && NULL != transf->pReadData )
  634. {
  635. if( ((ptrdiff_t)transf->pDefaultBuffer + transf->size
  636. >=
  637. (ptrdiff_t)transf->pWriteData )
  638. &&
  639. ((ptrdiff_t)transf->pDefaultBuffer + transf->size
  640. >=
  641. (ptrdiff_t)transf->pReadData )
  642. &&
  643. ((ptrdiff_t)transf->pReadData <= (ptrdiff_t)transf->pWriteData)
  644. )
  645. {
  646. return true;
  647. }
  648. }
  649. return false;
  650. }
  651. #endif
  652. #if USB_TRANSFER_SUPPORT_FLAGS
  653. // @usb_transfer_modify_flags
  654. // Modifies the user-dependent general-purpose flags using specified mask @mask and value @value
  655. // Returns: true if no error occurred, false otherwise.
  656. bool usb_transfer_modify_flags( sUSBTransfer_t * transf, tUSBTransferFlags_t mask, tUSBTransferFlags_t value )
  657. {
  658. if( NULL != transf )
  659. {
  660. // Modify only the bits that are not locked by @flagsLock
  661. transf->flags = ((transf->flags & (~transf->flagsLock)) & (~mask)) | (mask & value) | (transf->flags & transf->flagsLock);
  662. return true;
  663. }
  664. return false;
  665. }
  666. // @usb_transfer_modify_flags_locks
  667. // Modifies the lock mask for user-dependent general-purpose flags using specified mask @mask and value @value
  668. // Returns: true if no error occurred, false otherwise.
  669. bool usb_transfer_modify_flags_locks( sUSBTransfer_t * transf, tUSBTransferFlags_t lockMask, tUSBTransferFlags_t lockValue )
  670. {
  671. if( NULL != transf )
  672. {
  673. transf->flagsLock = (transf->flagsLock & (~lockMask)) | (lockMask & lockValue);
  674. return true;
  675. }
  676. return false;
  677. }
  678. // @usb_transfer_check_flags_wo_checking
  679. //
  680. static bool usb_transfer_check_flags_wo_checking( sUSBTransfer_t * transf, tUSBTransferFlags_t mask, tUSBTransferFlags_t value, eUSBTransferFlagMode_t mode )
  681. {
  682. uint32_t value1 = (transf->flags & mask);
  683. uint32_t value2 = (value & mask);
  684. if( eUSBTransferFlagMode_Or == mode )
  685. {
  686. return (0 != ((~(value1 ^ value2)) & mask));
  687. }
  688. else
  689. {
  690. return (0 == (value1 ^ value2));
  691. }
  692. }
  693. // @usb_transfer_check_flags
  694. // Check if the user-dependent general-purpose flags fit to the specified mask @mask and value @value using comparing method @mode.
  695. // @transf - the transfer object to operate with;
  696. // @mask - specified mask to check
  697. // @value - specified value to check
  698. // @mode - comparing method:
  699. // - eUSBTransferFlagMode_Or: at least one transfer bit-flag must be equal to the specified value;
  700. // - eUSBTransferFlagMode_And: all the transfer bit-flag must be equal to the specified value;
  701. // @pResult = the pointer to receive output result
  702. // Returns: true if no error occurred, false otherwise.
  703. bool usb_transfer_check_flags( sUSBTransfer_t * transf, tUSBTransferFlags_t mask, tUSBTransferFlags_t value, eUSBTransferFlagMode_t mode, bool * pResult )
  704. {
  705. if( (NULL != transf) && (NULL != pResult) )
  706. {
  707. *pResult = usb_transfer_check_flags_wo_checking( transf, mask, value, mode );
  708. return true;
  709. }
  710. return false;
  711. }
  712. // @usb_transfer_check_flags_fast
  713. // Check if the user-dependent general-purpose flags fit to the specified mask @mask and value @value using comparing method @mode.
  714. // @transf - the transfer object to operate with;
  715. // @mask - specified mask to check
  716. // @value - specified value to check
  717. // @mode - comparing method:
  718. // - eUSBTransferFlagMode_Or: at least one transfer bit-flag must be equal to the specified value;
  719. // - eUSBTransferFlagMode_And: all the transfer bit-flag must be equal to the specified value;
  720. // Returns: true if no error occurred and the comparing output is TRUE, false otherwise.
  721. // Note: you can use this function instead of @usb_transfer_check_flags if you are sure that the @transf pointer is valid.
  722. bool usb_transfer_check_flags_fast( sUSBTransfer_t * transf, tUSBTransferFlags_t mask, tUSBTransferFlags_t value, eUSBTransferFlagMode_t mode )
  723. {
  724. if( NULL != transf )
  725. {
  726. return usb_transfer_check_flags_wo_checking( transf, mask, value, mode );
  727. }
  728. return false;
  729. }
  730. #endif