|
7 | 7 | #if !defined(SPI_INTERFACES_COUNT) || \ |
8 | 8 | (defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0)) |
9 | 9 |
|
10 | | -//#define DEBUG_SERIAL Serial |
| 10 | +// #define DEBUG_SERIAL Serial |
11 | 11 |
|
12 | 12 | #ifdef DEBUG_SERIAL |
13 | 13 | template <typename T> |
14 | | -static void printChunk(const char *title, const T &buffer, const uint8_t size, |
15 | | - const uint16_t chunkNumber) { |
| 14 | +static void printChunk(const char *title, const T &buffer, const uint8_t size) { |
16 | 15 | DEBUG_SERIAL.print(F("\t")); |
17 | 16 | DEBUG_SERIAL.print(title); |
18 | | - DEBUG_SERIAL.print(F(" Chunk #")); |
19 | | - DEBUG_SERIAL.print(chunkNumber); |
20 | | - DEBUG_SERIAL.print(F(", size ")); |
| 17 | + DEBUG_SERIAL.print(F(" Chunk, size ")); |
21 | 18 | DEBUG_SERIAL.println(size); |
22 | 19 | DEBUG_SERIAL.print(F("\t")); |
23 | 20 |
|
@@ -45,6 +42,21 @@ static void printBuffer(const char *title, const uint8_t *buffer, |
45 | 42 | } |
46 | 43 | #endif |
47 | 44 |
|
| 45 | +// The Arduino Core of AVR defines min() as a macro. It also has no std::min, so |
| 46 | +// undef the macro and create std::min |
| 47 | +#if defined(__AVR__) |
| 48 | +#undef min |
| 49 | +namespace std { |
| 50 | +template <typename T> constexpr T min(const T a, const T b) { |
| 51 | + if (a < b) { |
| 52 | + return a; |
| 53 | + } else { |
| 54 | + return b; |
| 55 | + } |
| 56 | +} |
| 57 | +}; // namespace std |
| 58 | +#endif |
| 59 | + |
48 | 60 | /*! |
49 | 61 | * @brief Create an SPI device with the given CS pin and settings |
50 | 62 | * @param cspin The arduino pin number to use for chip select |
@@ -351,67 +363,119 @@ void Adafruit_SPIDevice::endTransactionWithDeassertingCS() { |
351 | 363 | endTransaction(); |
352 | 364 | } |
353 | 365 |
|
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; |
| 366 | +void Adafruit_SPIDevice::transferFilledChunk( |
| 367 | + ChunkBuffer &chunkBuffer, ChunkBuffer::Iterator &iteratorToIncrement, |
| 368 | + const uint8_t *bufferToSend, const size_t bufferLen) { |
| 369 | + auto bytesToTransferLen = bufferLen; |
| 370 | + auto bytesToTransferBuffer = bufferToSend; |
369 | 371 |
|
370 | | - auto chunkBufferIterator = chunkBuffer.begin(); |
| 372 | + while (bytesToTransferLen) { |
| 373 | + auto bytesToTransferLenThisChunk = std::min( |
| 374 | + bytesToTransferLen, |
| 375 | + chunkBuffer.size() - (iteratorToIncrement - chunkBuffer.begin())); |
371 | 376 |
|
372 | | -#ifdef DEBUG_SERIAL |
373 | | - uint8_t chunkNumber = 1; |
374 | | -#endif |
| 377 | + memcpy(iteratorToIncrement, bytesToTransferBuffer, |
| 378 | + bytesToTransferLenThisChunk); |
375 | 379 |
|
376 | | - beginTransactionWithAssertingCS(); |
| 380 | + bytesToTransferLen -= bytesToTransferLenThisChunk; |
| 381 | + bytesToTransferBuffer += bytesToTransferLenThisChunk; |
377 | 382 |
|
378 | | - for (size_t i = 0; i < prefix_len; ++i) { |
379 | | - *chunkBufferIterator++ = prefix_buffer[i]; |
| 383 | + if (bytesToTransferLen) { |
| 384 | + transfer(chunkBuffer.data(), chunkBuffer.size()); |
380 | 385 |
|
381 | | - if (chunkBufferIterator == chunkBuffer.end()) { |
382 | | - transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer); |
383 | | - chunkBufferIterator = chunkBuffer.begin(); |
| 386 | + iteratorToIncrement = chunkBuffer.begin(); |
384 | 387 |
|
385 | 388 | #ifdef DEBUG_SERIAL |
386 | | - printChunk("write() Wrote", chunkBuffer, maxBufferSizeForChunkedTransfer, |
387 | | - chunkNumber++); |
| 389 | + printChunk("transferFilledChunk()", chunkBuffer, chunkBuffer.size()); |
388 | 390 | #endif |
| 391 | + } else { |
| 392 | + iteratorToIncrement = iteratorToIncrement + bytesToTransferLenThisChunk; |
389 | 393 | } |
390 | 394 | } |
| 395 | +} |
391 | 396 |
|
392 | | - for (size_t i = 0; i < len; ++i) { |
393 | | - *chunkBufferIterator++ = buffer[i]; |
| 397 | +void Adafruit_SPIDevice::transferPartiallyFilledChunk( |
| 398 | + ChunkBuffer &chunkBuffer, |
| 399 | + const ChunkBuffer::Iterator &chunkBufferIterator) { |
| 400 | + if (chunkBufferIterator != chunkBuffer.begin()) { |
| 401 | + auto bytesToTransferLenThisChunk = |
| 402 | + chunkBufferIterator - chunkBuffer.begin(); |
394 | 403 |
|
395 | | - if (chunkBufferIterator == chunkBuffer.end()) { |
396 | | - transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer); |
397 | | - chunkBufferIterator = chunkBuffer.begin(); |
| 404 | + transfer(chunkBuffer.data(), bytesToTransferLenThisChunk); |
398 | 405 |
|
399 | 406 | #ifdef DEBUG_SERIAL |
400 | | - printChunk("write() Wrote", chunkBuffer, maxBufferSizeForChunkedTransfer, |
401 | | - chunkNumber++); |
| 407 | + printChunk("transferPartiallyFilledChunk()", chunkBuffer, |
| 408 | + bytesToTransferLenThisChunk); |
402 | 409 | #endif |
403 | | - } |
404 | 410 | } |
| 411 | +} |
405 | 412 |
|
406 | | - if (chunkBufferIterator != chunkBuffer.begin()) { |
407 | | - auto numberByteToTransfer = chunkBufferIterator - chunkBuffer.begin(); |
408 | | - transfer(chunkBuffer.data(), numberByteToTransfer); |
| 413 | +void Adafruit_SPIDevice::transferAndReadChunks( |
| 414 | + ChunkBuffer &chunkBuffer, ChunkBuffer::Iterator &iteratorToIncrement, |
| 415 | + uint8_t *readBuffer, const size_t readLen, const uint8_t sendVal) { |
| 416 | + size_t bytesToTransferLen = readLen; |
| 417 | + auto readFromIterator = iteratorToIncrement; |
| 418 | + |
| 419 | + while (bytesToTransferLen) { |
| 420 | + auto bytesToTransferLenThisChunk = std::min( |
| 421 | + bytesToTransferLen, |
| 422 | + chunkBuffer.size() - (iteratorToIncrement - chunkBuffer.begin())); |
| 423 | + |
| 424 | + memset(iteratorToIncrement, sendVal, bytesToTransferLenThisChunk); |
409 | 425 |
|
| 426 | + bytesToTransferLen -= bytesToTransferLenThisChunk; |
| 427 | + |
| 428 | + { |
| 429 | + auto tranferLen = readFromIterator == chunkBuffer.begin() |
| 430 | + ? bytesToTransferLenThisChunk |
| 431 | + : chunkBuffer.size(); |
| 432 | +#if defined(DEBUG_SERIAL) && defined(DEBUG_VERBOSE) |
| 433 | + printChunk("transferAndReadChunks() before transmit", chunkBuffer, |
| 434 | + tranferLen); |
| 435 | +#endif |
| 436 | + transfer(chunkBuffer.data(), tranferLen); |
410 | 437 | #ifdef DEBUG_SERIAL |
411 | | - printChunk("write() Wrote remaining", chunkBuffer, numberByteToTransfer, |
412 | | - chunkNumber++); |
| 438 | + printChunk("transferAndReadChunks() after transmit", chunkBuffer, |
| 439 | + tranferLen); |
413 | 440 | #endif |
| 441 | + } |
| 442 | + |
| 443 | + memcpy(readFromIterator, readBuffer, bytesToTransferLenThisChunk); |
| 444 | + |
| 445 | + readBuffer += bytesToTransferLenThisChunk; |
| 446 | + |
| 447 | + readFromIterator = iteratorToIncrement = chunkBuffer.begin(); |
| 448 | + |
| 449 | + if (!bytesToTransferLen) { |
| 450 | + break; |
| 451 | + } |
414 | 452 | } |
| 453 | +} |
| 454 | + |
| 455 | +/*! |
| 456 | + * @brief Write a buffer or two to the SPI device, with transaction |
| 457 | + * management. |
| 458 | + * @param buffer Pointer to buffer of data to write |
| 459 | + * @param len Number of bytes from buffer to write |
| 460 | + * @param prefix_buffer Pointer to optional array of data to write before |
| 461 | + * buffer. |
| 462 | + * @param prefix_len Number of bytes from prefix buffer to write |
| 463 | + * @return Always returns true because there's no way to test success of SPI |
| 464 | + * writes |
| 465 | + */ |
| 466 | +bool Adafruit_SPIDevice::write(const uint8_t *buffer, size_t len, |
| 467 | + const uint8_t *prefix_buffer, |
| 468 | + size_t prefix_len) { |
| 469 | + Array<uint8_t, maxBufferSizeForChunkedTransfer> chunkBuffer; |
| 470 | + |
| 471 | + auto chunkBufferIterator = chunkBuffer.begin(); |
| 472 | + |
| 473 | + beginTransactionWithAssertingCS(); |
| 474 | + |
| 475 | + transferFilledChunk(chunkBuffer, chunkBufferIterator, prefix_buffer, |
| 476 | + prefix_len); |
| 477 | + transferFilledChunk(chunkBuffer, chunkBufferIterator, buffer, len); |
| 478 | + transferPartiallyFilledChunk(chunkBuffer, chunkBufferIterator); |
415 | 479 |
|
416 | 480 | endTransactionWithDeassertingCS(); |
417 | 481 |
|
@@ -462,84 +526,12 @@ bool Adafruit_SPIDevice::write_then_read(const uint8_t *write_buffer, |
462 | 526 |
|
463 | 527 | auto chunkBufferIterator = chunkBuffer.begin(); |
464 | 528 |
|
465 | | -#ifdef DEBUG_SERIAL |
466 | | - uint8_t chunkNumber = 1; |
467 | | -#endif |
468 | | - |
469 | 529 | beginTransactionWithAssertingCS(); |
470 | 530 |
|
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 | | - } |
| 531 | + transferFilledChunk(chunkBuffer, chunkBufferIterator, write_buffer, |
| 532 | + write_len); |
| 533 | + transferAndReadChunks(chunkBuffer, chunkBufferIterator, read_buffer, read_len, |
| 534 | + sendvalue); |
543 | 535 |
|
544 | 536 | endTransactionWithDeassertingCS(); |
545 | 537 |
|
|
0 commit comments