|
1 | 1 | #include "Adafruit_SPIDevice.h"
|
2 | 2 |
|
3 |
| -#if !defined(__AVR__) |
4 |
| -#include <array> |
5 |
| -#endif |
6 |
| - |
7 | 3 | #if !defined(SPI_INTERFACES_COUNT) || \
|
8 | 4 | (defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0))
|
9 | 5 |
|
10 |
| -//#define DEBUG_SERIAL Serial |
| 6 | +// #define DEBUG_SERIAL Serial |
11 | 7 |
|
12 | 8 | #ifdef DEBUG_SERIAL
|
13 | 9 | template <typename T>
|
14 |
| -static void printChunk(const char *title, const T &buffer, const uint8_t size, |
15 |
| - const uint16_t chunkNumber) { |
| 10 | +static void printChunk(const char *title, const T &buffer, const uint8_t size) { |
16 | 11 | DEBUG_SERIAL.print(F("\t"));
|
17 | 12 | DEBUG_SERIAL.print(title);
|
18 |
| - DEBUG_SERIAL.print(F(" Chunk #")); |
19 |
| - DEBUG_SERIAL.print(chunkNumber); |
20 |
| - DEBUG_SERIAL.print(F(", size ")); |
| 13 | + DEBUG_SERIAL.print(F(" Chunk, size ")); |
21 | 14 | DEBUG_SERIAL.println(size);
|
22 | 15 | DEBUG_SERIAL.print(F("\t"));
|
23 | 16 |
|
@@ -45,6 +38,20 @@ static void printBuffer(const char *title, const uint8_t *buffer,
|
45 | 38 | }
|
46 | 39 | #endif
|
47 | 40 |
|
| 41 | +// The Arduino Core of AVR defines min() as a macro. It also has no std::min, so |
| 42 | +// undef the macro and create std::min |
| 43 | +#if defined(__AVR__) |
| 44 | +#undef min |
| 45 | +namespace std { |
| 46 | +template <typename T> constexpr T min(const T a, const T b) { |
| 47 | + return (a < b) ? a : b; |
| 48 | +} |
| 49 | +}; // namespace std |
| 50 | +#else |
| 51 | +// all other platforms have stdlib's <algorithm>, so include the real deal |
| 52 | +#include <algorithm> |
| 53 | +#endif |
| 54 | + |
48 | 55 | /*!
|
49 | 56 | * @brief Create an SPI device with the given CS pin and settings
|
50 | 57 | * @param cspin The arduino pin number to use for chip select
|
@@ -351,67 +358,118 @@ void Adafruit_SPIDevice::endTransactionWithDeassertingCS() {
|
351 | 358 | endTransaction();
|
352 | 359 | }
|
353 | 360 |
|
354 |
| -/*! |
355 |
| - * @brief Write a buffer or two to the SPI device, with transaction |
356 |
| - * management. |
357 |
| - * @param buffer Pointer to buffer of data to write |
358 |
| - * @param len Number of bytes from buffer to write |
359 |
| - * @param prefix_buffer Pointer to optional array of data to write before |
360 |
| - * buffer. |
361 |
| - * @param prefix_len Number of bytes from prefix buffer to write |
362 |
| - * @return Always returns true because there's no way to test success of SPI |
363 |
| - * writes |
364 |
| - */ |
365 |
| -bool Adafruit_SPIDevice::write(const uint8_t *buffer, size_t len, |
366 |
| - const uint8_t *prefix_buffer, |
367 |
| - size_t prefix_len) { |
368 |
| - Array<uint8_t, maxBufferSizeForChunkedTransfer> chunkBuffer; |
| 361 | +void Adafruit_SPIDevice::transferFilledChunk( |
| 362 | + ChunkBuffer &chunkBuffer, ChunkBuffer::Iterator &iteratorToIncrement, |
| 363 | + const uint8_t *bufferToSend, const size_t bufferLen) { |
| 364 | + auto bytesToTransferLen = bufferLen; |
| 365 | + auto bytesToTransferBuffer = bufferToSend; |
369 | 366 |
|
370 |
| - auto chunkBufferIterator = chunkBuffer.begin(); |
| 367 | + while (bytesToTransferLen) { |
| 368 | + auto bytesToTransferLenThisChunk = std::min( |
| 369 | + bytesToTransferLen, |
| 370 | + chunkBuffer.size() - (iteratorToIncrement - chunkBuffer.begin())); |
371 | 371 |
|
372 |
| -#ifdef DEBUG_SERIAL |
373 |
| - uint8_t chunkNumber = 1; |
374 |
| -#endif |
| 372 | + memcpy(iteratorToIncrement, bytesToTransferBuffer, |
| 373 | + bytesToTransferLenThisChunk); |
375 | 374 |
|
376 |
| - beginTransactionWithAssertingCS(); |
| 375 | + bytesToTransferLen -= bytesToTransferLenThisChunk; |
| 376 | + bytesToTransferBuffer += bytesToTransferLenThisChunk; |
377 | 377 |
|
378 |
| - for (size_t i = 0; i < prefix_len; ++i) { |
379 |
| - *chunkBufferIterator++ = prefix_buffer[i]; |
| 378 | + if (bytesToTransferLen) { |
| 379 | + transfer(chunkBuffer.data(), chunkBuffer.size()); |
380 | 380 |
|
381 |
| - if (chunkBufferIterator == chunkBuffer.end()) { |
382 |
| - transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer); |
383 |
| - chunkBufferIterator = chunkBuffer.begin(); |
| 381 | + iteratorToIncrement = chunkBuffer.begin(); |
384 | 382 |
|
385 | 383 | #ifdef DEBUG_SERIAL
|
386 |
| - printChunk("write() Wrote", chunkBuffer, maxBufferSizeForChunkedTransfer, |
387 |
| - chunkNumber++); |
| 384 | + printChunk("transferFilledChunk()", chunkBuffer, chunkBuffer.size()); |
388 | 385 | #endif
|
| 386 | + } else { |
| 387 | + iteratorToIncrement = iteratorToIncrement + bytesToTransferLenThisChunk; |
389 | 388 | }
|
390 | 389 | }
|
| 390 | +} |
391 | 391 |
|
392 |
| - for (size_t i = 0; i < len; ++i) { |
393 |
| - *chunkBufferIterator++ = buffer[i]; |
| 392 | +void Adafruit_SPIDevice::transferPartiallyFilledChunk( |
| 393 | + ChunkBuffer &chunkBuffer, |
| 394 | + const ChunkBuffer::Iterator &chunkBufferIterator) { |
| 395 | + if (chunkBufferIterator != chunkBuffer.begin()) { |
| 396 | + auto bytesToTransferLenThisChunk = |
| 397 | + chunkBufferIterator - chunkBuffer.begin(); |
394 | 398 |
|
395 |
| - if (chunkBufferIterator == chunkBuffer.end()) { |
396 |
| - transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer); |
397 |
| - chunkBufferIterator = chunkBuffer.begin(); |
| 399 | + transfer(chunkBuffer.data(), bytesToTransferLenThisChunk); |
398 | 400 |
|
399 | 401 | #ifdef DEBUG_SERIAL
|
400 |
| - printChunk("write() Wrote", chunkBuffer, maxBufferSizeForChunkedTransfer, |
401 |
| - chunkNumber++); |
| 402 | + printChunk("transferPartiallyFilledChunk()", chunkBuffer, |
| 403 | + bytesToTransferLenThisChunk); |
402 | 404 | #endif
|
403 |
| - } |
404 | 405 | }
|
| 406 | +} |
405 | 407 |
|
406 |
| - if (chunkBufferIterator != chunkBuffer.begin()) { |
407 |
| - auto numberByteToTransfer = chunkBufferIterator - chunkBuffer.begin(); |
408 |
| - transfer(chunkBuffer.data(), numberByteToTransfer); |
| 408 | +void Adafruit_SPIDevice::transferAndReadChunks( |
| 409 | + ChunkBuffer &chunkBuffer, ChunkBuffer::Iterator &iteratorToIncrement, |
| 410 | + uint8_t *readBuffer, const size_t readLen, const uint8_t sendVal) { |
| 411 | + size_t bytesToTransferLen = readLen; |
| 412 | + auto readFromIterator = iteratorToIncrement; |
| 413 | + |
| 414 | + while (bytesToTransferLen) { |
| 415 | + auto bytesToTransferLenThisChunk = std::min( |
| 416 | + bytesToTransferLen, |
| 417 | + chunkBuffer.size() - (iteratorToIncrement - chunkBuffer.begin())); |
409 | 418 |
|
| 419 | + memset(iteratorToIncrement, sendVal, bytesToTransferLenThisChunk); |
| 420 | + |
| 421 | + iteratorToIncrement += bytesToTransferLenThisChunk; |
| 422 | + bytesToTransferLen -= bytesToTransferLenThisChunk; |
| 423 | + |
| 424 | + { |
| 425 | + auto tranferLen = iteratorToIncrement - chunkBuffer.begin(); |
| 426 | +#if defined(DEBUG_SERIAL) && defined(DEBUG_VERBOSE) |
| 427 | + printChunk("transferAndReadChunks() before transmit", chunkBuffer, |
| 428 | + tranferLen); |
| 429 | +#endif |
| 430 | + transfer(chunkBuffer.data(), tranferLen); |
410 | 431 | #ifdef DEBUG_SERIAL
|
411 |
| - printChunk("write() Wrote remaining", chunkBuffer, numberByteToTransfer, |
412 |
| - chunkNumber++); |
| 432 | + printChunk("transferAndReadChunks() after transmit", chunkBuffer, |
| 433 | + tranferLen); |
413 | 434 | #endif
|
| 435 | + } |
| 436 | + |
| 437 | + memcpy(readBuffer, readFromIterator, bytesToTransferLenThisChunk); |
| 438 | + |
| 439 | + readBuffer += bytesToTransferLenThisChunk; |
| 440 | + |
| 441 | + readFromIterator = iteratorToIncrement = chunkBuffer.begin(); |
| 442 | + |
| 443 | + if (!bytesToTransferLen) { |
| 444 | + break; |
| 445 | + } |
414 | 446 | }
|
| 447 | +} |
| 448 | + |
| 449 | +/*! |
| 450 | + * @brief Write a buffer or two to the SPI device, with transaction |
| 451 | + * management. |
| 452 | + * @param buffer Pointer to buffer of data to write |
| 453 | + * @param len Number of bytes from buffer to write |
| 454 | + * @param prefix_buffer Pointer to optional array of data to write before |
| 455 | + * buffer. |
| 456 | + * @param prefix_len Number of bytes from prefix buffer to write |
| 457 | + * @return Always returns true because there's no way to test success of SPI |
| 458 | + * writes |
| 459 | + */ |
| 460 | +bool Adafruit_SPIDevice::write(const uint8_t *buffer, size_t len, |
| 461 | + const uint8_t *prefix_buffer, |
| 462 | + size_t prefix_len) { |
| 463 | + Array<uint8_t, maxBufferSizeForChunkedTransfer> chunkBuffer; |
| 464 | + |
| 465 | + auto chunkBufferIterator = chunkBuffer.begin(); |
| 466 | + |
| 467 | + beginTransactionWithAssertingCS(); |
| 468 | + |
| 469 | + transferFilledChunk(chunkBuffer, chunkBufferIterator, prefix_buffer, |
| 470 | + prefix_len); |
| 471 | + transferFilledChunk(chunkBuffer, chunkBufferIterator, buffer, len); |
| 472 | + transferPartiallyFilledChunk(chunkBuffer, chunkBufferIterator); |
415 | 473 |
|
416 | 474 | endTransactionWithDeassertingCS();
|
417 | 475 |
|
@@ -462,84 +520,12 @@ bool Adafruit_SPIDevice::write_then_read(const uint8_t *write_buffer,
|
462 | 520 |
|
463 | 521 | auto chunkBufferIterator = chunkBuffer.begin();
|
464 | 522 |
|
465 |
| -#ifdef DEBUG_SERIAL |
466 |
| - uint8_t chunkNumber = 1; |
467 |
| -#endif |
468 |
| - |
469 | 523 | beginTransactionWithAssertingCS();
|
470 | 524 |
|
471 |
| - for (size_t i = 0; i < write_len; ++i) { |
472 |
| - *chunkBufferIterator++ = write_buffer[i]; |
473 |
| - |
474 |
| - if (chunkBufferIterator == chunkBuffer.end()) { |
475 |
| - transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer); |
476 |
| - chunkBufferIterator = chunkBuffer.begin(); |
477 |
| - |
478 |
| -#ifdef DEBUG_SERIAL |
479 |
| - printChunk("write_then_read() Wrote", chunkBuffer, |
480 |
| - maxBufferSizeForChunkedTransfer, chunkNumber++); |
481 |
| -#endif |
482 |
| - } |
483 |
| - } |
484 |
| - |
485 |
| - auto readBufferIterator = read_buffer; |
486 |
| - auto readFromIterator = chunkBufferIterator; |
487 |
| - size_t readBufferLen = read_len; |
488 |
| - |
489 |
| - for (size_t i = 0; i < read_len; ++i) { |
490 |
| - *chunkBufferIterator++ = sendvalue; |
491 |
| - |
492 |
| - if (chunkBufferIterator == chunkBuffer.end()) { |
493 |
| -#ifdef DEBUG_SERIAL |
494 |
| - printChunk("write_then_read() before transmit", chunkBuffer, |
495 |
| - maxBufferSizeForChunkedTransfer, chunkNumber); |
496 |
| -#endif |
497 |
| - |
498 |
| - transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer); |
499 |
| - |
500 |
| - while (readBufferLen) { |
501 |
| - if (readFromIterator != chunkBuffer.end()) { |
502 |
| - *readBufferIterator++ = *readFromIterator++; |
503 |
| - --readBufferLen; |
504 |
| - } else { |
505 |
| - break; |
506 |
| - } |
507 |
| - } |
508 |
| - |
509 |
| -#ifdef DEBUG_SERIAL |
510 |
| - printChunk("write_then_read() after transmit", chunkBuffer, |
511 |
| - maxBufferSizeForChunkedTransfer, chunkNumber++); |
512 |
| -#endif |
513 |
| - |
514 |
| - chunkBufferIterator = chunkBuffer.begin(); |
515 |
| - readFromIterator = chunkBuffer.begin(); |
516 |
| - } |
517 |
| - } |
518 |
| - |
519 |
| - if (chunkBufferIterator != chunkBuffer.begin()) { |
520 |
| - auto numberByteToTransfer = chunkBufferIterator - chunkBuffer.begin(); |
521 |
| - |
522 |
| -#ifdef DEBUG_SERIAL |
523 |
| - printChunk("write_then_read() before transmit remaining", chunkBuffer, |
524 |
| - numberByteToTransfer, chunkNumber); |
525 |
| -#endif |
526 |
| - |
527 |
| - transfer(chunkBuffer.data(), numberByteToTransfer); |
528 |
| - |
529 |
| -#ifdef DEBUG_SERIAL |
530 |
| - printChunk("write_then_read() after transmit remaining", chunkBuffer, |
531 |
| - numberByteToTransfer, chunkNumber); |
532 |
| -#endif |
533 |
| - |
534 |
| - while (readBufferLen) { |
535 |
| - if (readFromIterator != chunkBuffer.end()) { |
536 |
| - *readBufferIterator++ = *readFromIterator++; |
537 |
| - --readBufferLen; |
538 |
| - } else { |
539 |
| - break; |
540 |
| - } |
541 |
| - } |
542 |
| - } |
| 525 | + transferFilledChunk(chunkBuffer, chunkBufferIterator, write_buffer, |
| 526 | + write_len); |
| 527 | + transferAndReadChunks(chunkBuffer, chunkBufferIterator, read_buffer, read_len, |
| 528 | + sendvalue); |
543 | 529 |
|
544 | 530 | endTransactionWithDeassertingCS();
|
545 | 531 |
|
|
0 commit comments