|
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 | + auto 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