Skip to content

Commit

Permalink
moved the chunked transfer management to their own private methods
Browse files Browse the repository at this point in the history
  • Loading branch information
eringerli committed May 15, 2022
1 parent f08f376 commit a97c62a
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 153 deletions.
238 changes: 112 additions & 126 deletions Adafruit_SPIDevice.cpp
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
#include "Adafruit_SPIDevice.h"

#if !defined(__AVR__)
#include <array>
#endif

#if !defined(SPI_INTERFACES_COUNT) || \
(defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0))

//#define DEBUG_SERIAL Serial
// #define DEBUG_SERIAL Serial

#ifdef DEBUG_SERIAL
template <typename T>
static void printChunk(const char *title, const T &buffer, const uint8_t size,
const uint16_t chunkNumber) {
static void printChunk(const char *title, const T &buffer, const uint8_t size) {
DEBUG_SERIAL.print(F("\t"));
DEBUG_SERIAL.print(title);
DEBUG_SERIAL.print(F(" Chunk #"));
DEBUG_SERIAL.print(chunkNumber);
DEBUG_SERIAL.print(F(", size "));
DEBUG_SERIAL.print(F(" Chunk, size "));
DEBUG_SERIAL.println(size);
DEBUG_SERIAL.print(F("\t"));

Expand Down Expand Up @@ -45,6 +38,20 @@ static void printBuffer(const char *title, const uint8_t *buffer,
}
#endif

// The Arduino Core of AVR defines min() as a macro. It also has no std::min, so
// undef the macro and create std::min
#if defined(__AVR__)
#undef min
namespace std {
template <typename T> constexpr T min(const T a, const T b) {
return (a < b) ? a : b;
}
}; // namespace std
#else
// all other platforms have stdlib's <algorithm>, so include the real deal
#include <algorithm>
#endif

/*!
* @brief Create an SPI device with the given CS pin and settings
* @param cspin The arduino pin number to use for chip select
Expand Down Expand Up @@ -351,67 +358,118 @@ void Adafruit_SPIDevice::endTransactionWithDeassertingCS() {
endTransaction();
}

/*!
* @brief Write a buffer or two to the SPI device, with transaction
* management.
* @param buffer Pointer to buffer of data to write
* @param len Number of bytes from buffer to write
* @param prefix_buffer Pointer to optional array of data to write before
* buffer.
* @param prefix_len Number of bytes from prefix buffer to write
* @return Always returns true because there's no way to test success of SPI
* writes
*/
bool Adafruit_SPIDevice::write(const uint8_t *buffer, size_t len,
const uint8_t *prefix_buffer,
size_t prefix_len) {
Array<uint8_t, maxBufferSizeForChunkedTransfer> chunkBuffer;
void Adafruit_SPIDevice::transferFilledChunk(
ChunkBuffer &chunkBuffer, ChunkBuffer::Iterator &iteratorToIncrement,
const uint8_t *bufferToSend, const size_t bufferLen) {
auto bytesToTransferLen = bufferLen;
auto bytesToTransferBuffer = bufferToSend;

auto chunkBufferIterator = chunkBuffer.begin();
while (bytesToTransferLen) {
auto bytesToTransferLenThisChunk = std::min(
bytesToTransferLen,
chunkBuffer.size() - (iteratorToIncrement - chunkBuffer.begin()));

#ifdef DEBUG_SERIAL
uint8_t chunkNumber = 1;
#endif
memcpy(iteratorToIncrement, bytesToTransferBuffer,
bytesToTransferLenThisChunk);

beginTransactionWithAssertingCS();
bytesToTransferLen -= bytesToTransferLenThisChunk;
bytesToTransferBuffer += bytesToTransferLenThisChunk;

for (size_t i = 0; i < prefix_len; ++i) {
*chunkBufferIterator++ = prefix_buffer[i];
if (bytesToTransferLen) {
transfer(chunkBuffer.data(), chunkBuffer.size());

if (chunkBufferIterator == chunkBuffer.end()) {
transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer);
chunkBufferIterator = chunkBuffer.begin();
iteratorToIncrement = chunkBuffer.begin();

#ifdef DEBUG_SERIAL
printChunk("write() Wrote", chunkBuffer, maxBufferSizeForChunkedTransfer,
chunkNumber++);
printChunk("transferFilledChunk()", chunkBuffer, chunkBuffer.size());
#endif
} else {
iteratorToIncrement = iteratorToIncrement + bytesToTransferLenThisChunk;
}
}
}

for (size_t i = 0; i < len; ++i) {
*chunkBufferIterator++ = buffer[i];
void Adafruit_SPIDevice::transferPartiallyFilledChunk(
ChunkBuffer &chunkBuffer,
const ChunkBuffer::Iterator &chunkBufferIterator) {
if (chunkBufferIterator != chunkBuffer.begin()) {
auto bytesToTransferLenThisChunk =
chunkBufferIterator - chunkBuffer.begin();

if (chunkBufferIterator == chunkBuffer.end()) {
transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer);
chunkBufferIterator = chunkBuffer.begin();
transfer(chunkBuffer.data(), bytesToTransferLenThisChunk);

#ifdef DEBUG_SERIAL
printChunk("write() Wrote", chunkBuffer, maxBufferSizeForChunkedTransfer,
chunkNumber++);
printChunk("transferPartiallyFilledChunk()", chunkBuffer,
bytesToTransferLenThisChunk);
#endif
}
}
}

if (chunkBufferIterator != chunkBuffer.begin()) {
auto numberByteToTransfer = chunkBufferIterator - chunkBuffer.begin();
transfer(chunkBuffer.data(), numberByteToTransfer);
void Adafruit_SPIDevice::transferAndReadChunks(
ChunkBuffer &chunkBuffer, ChunkBuffer::Iterator &iteratorToIncrement,
uint8_t *readBuffer, const size_t readLen, const uint8_t sendVal) {
auto bytesToTransferLen = readLen;
auto readFromIterator = iteratorToIncrement;

while (bytesToTransferLen) {
auto bytesToTransferLenThisChunk = std::min(
bytesToTransferLen,
chunkBuffer.size() - (iteratorToIncrement - chunkBuffer.begin()));

memset(iteratorToIncrement, sendVal, bytesToTransferLenThisChunk);

iteratorToIncrement += bytesToTransferLenThisChunk;
bytesToTransferLen -= bytesToTransferLenThisChunk;

{
auto tranferLen = iteratorToIncrement - chunkBuffer.begin();
#if defined(DEBUG_SERIAL) && defined(DEBUG_VERBOSE)
printChunk("transferAndReadChunks() before transmit", chunkBuffer,
tranferLen);
#endif
transfer(chunkBuffer.data(), tranferLen);
#ifdef DEBUG_SERIAL
printChunk("write() Wrote remaining", chunkBuffer, numberByteToTransfer,
chunkNumber++);
printChunk("transferAndReadChunks() after transmit", chunkBuffer,
tranferLen);
#endif
}

memcpy(readBuffer, readFromIterator, bytesToTransferLenThisChunk);

readBuffer += bytesToTransferLenThisChunk;

readFromIterator = iteratorToIncrement = chunkBuffer.begin();

if (!bytesToTransferLen) {
break;
}
}
}

/*!
* @brief Write a buffer or two to the SPI device, with transaction
* management.
* @param buffer Pointer to buffer of data to write
* @param len Number of bytes from buffer to write
* @param prefix_buffer Pointer to optional array of data to write before
* buffer.
* @param prefix_len Number of bytes from prefix buffer to write
* @return Always returns true because there's no way to test success of SPI
* writes
*/
bool Adafruit_SPIDevice::write(const uint8_t *buffer, size_t len,
const uint8_t *prefix_buffer,
size_t prefix_len) {
Array<uint8_t, maxBufferSizeForChunkedTransfer> chunkBuffer;

auto chunkBufferIterator = chunkBuffer.begin();

beginTransactionWithAssertingCS();

transferFilledChunk(chunkBuffer, chunkBufferIterator, prefix_buffer,
prefix_len);
transferFilledChunk(chunkBuffer, chunkBufferIterator, buffer, len);
transferPartiallyFilledChunk(chunkBuffer, chunkBufferIterator);

endTransactionWithDeassertingCS();

Expand Down Expand Up @@ -462,84 +520,12 @@ bool Adafruit_SPIDevice::write_then_read(const uint8_t *write_buffer,

auto chunkBufferIterator = chunkBuffer.begin();

#ifdef DEBUG_SERIAL
uint8_t chunkNumber = 1;
#endif

beginTransactionWithAssertingCS();

for (size_t i = 0; i < write_len; ++i) {
*chunkBufferIterator++ = write_buffer[i];

if (chunkBufferIterator == chunkBuffer.end()) {
transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer);
chunkBufferIterator = chunkBuffer.begin();

#ifdef DEBUG_SERIAL
printChunk("write_then_read() Wrote", chunkBuffer,
maxBufferSizeForChunkedTransfer, chunkNumber++);
#endif
}
}

auto readBufferIterator = read_buffer;
auto readFromIterator = chunkBufferIterator;
size_t readBufferLen = read_len;

for (size_t i = 0; i < read_len; ++i) {
*chunkBufferIterator++ = sendvalue;

if (chunkBufferIterator == chunkBuffer.end()) {
#ifdef DEBUG_SERIAL
printChunk("write_then_read() before transmit", chunkBuffer,
maxBufferSizeForChunkedTransfer, chunkNumber);
#endif

transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer);

while (readBufferLen) {
if (readFromIterator != chunkBuffer.end()) {
*readBufferIterator++ = *readFromIterator++;
--readBufferLen;
} else {
break;
}
}

#ifdef DEBUG_SERIAL
printChunk("write_then_read() after transmit", chunkBuffer,
maxBufferSizeForChunkedTransfer, chunkNumber++);
#endif

chunkBufferIterator = chunkBuffer.begin();
readFromIterator = chunkBuffer.begin();
}
}

if (chunkBufferIterator != chunkBuffer.begin()) {
auto numberByteToTransfer = chunkBufferIterator - chunkBuffer.begin();

#ifdef DEBUG_SERIAL
printChunk("write_then_read() before transmit remaining", chunkBuffer,
numberByteToTransfer, chunkNumber);
#endif

transfer(chunkBuffer.data(), numberByteToTransfer);

#ifdef DEBUG_SERIAL
printChunk("write_then_read() after transmit remaining", chunkBuffer,
numberByteToTransfer, chunkNumber);
#endif

while (readBufferLen) {
if (readFromIterator != chunkBuffer.end()) {
*readBufferIterator++ = *readFromIterator++;
--readBufferLen;
} else {
break;
}
}
}
transferFilledChunk(chunkBuffer, chunkBufferIterator, write_buffer,
write_len);
transferAndReadChunks(chunkBuffer, chunkBufferIterator, read_buffer, read_len,
sendvalue);

endTransactionWithDeassertingCS();

Expand Down
70 changes: 43 additions & 27 deletions Adafruit_SPIDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,30 +103,6 @@ class Adafruit_SPIDevice {
void beginTransactionWithAssertingCS();
void endTransactionWithDeassertingCS();

private:
SPIClass *_spi;
SPISettings *_spiSetting;
uint32_t _freq;
BusIOBitOrder _dataOrder;
uint8_t _dataMode;

void setChipSelect(int value);

int8_t _cs, _sck, _mosi, _miso;
#ifdef BUSIO_USE_FAST_PINIO
BusIO_PortReg *mosiPort, *clkPort, *misoPort, *csPort;
BusIO_PortMask mosiPinMask, misoPinMask, clkPinMask, csPinMask;
#endif

//! constant for the buffer size for the chunked transfer
static constexpr size_t maxBufferSizeForChunkedTransfer =
#ifdef __AVR__
32;
#else
64;
#endif
bool _begun;

protected:
/*!
* @brief Template to encypsulate a C-array, provides STL-style accessors
Expand All @@ -136,15 +112,18 @@ class Adafruit_SPIDevice {
*/
template <typename Type, size_t Size> class Array {
public:
//! Iterator type
using Iterator = Type *;

/*! @brief returns a pointer the start of the buffer
* @returns a pointer the start of the buffer
*/
Type *begin() { return buffer; }
Iterator begin() { return buffer; }

/*! @brief returns a pointer the one increment beyond the end of the buffer
* @returns a pointer the one increment beyond the end of the buffer
*/
Type *end() { return endPointer; }
Iterator end() { return endPointer; }

/*! @brief returns the size of the buffer
* @returns the size of the buffer
Expand Down Expand Up @@ -172,8 +151,45 @@ class Adafruit_SPIDevice {
//! the buffer
Type buffer[Size];
//! address buffer one increment after the end
Type *endPointer = buffer + Size;
Iterator endPointer = buffer + Size;
};

private:
//! constant for the buffer size for the chunked transfer
static constexpr size_t maxBufferSizeForChunkedTransfer =
#ifdef __AVR__
32;
#else
64;
#endif

using ChunkBuffer = Array<uint8_t, maxBufferSizeForChunkedTransfer>;

SPIClass *_spi;
SPISettings *_spiSetting;
uint32_t _freq;
BusIOBitOrder _dataOrder;
uint8_t _dataMode;

void setChipSelect(int value);
void transferFilledChunk(ChunkBuffer &chunkBuffer,
ChunkBuffer::Iterator &iteratorToIncrement,
const uint8_t *bufferToSend, const size_t bufferLen);
void transferPartiallyFilledChunk(
ChunkBuffer &chunkBuffer,
const ChunkBuffer::Iterator &chunkBufferIterator);

void transferAndReadChunks(ChunkBuffer &chunkBuffer,
ChunkBuffer::Iterator &iteratorToIncrement,
uint8_t *readBuffer, const size_t readLen,
const uint8_t sendVal);

int8_t _cs, _sck, _mosi, _miso;
#ifdef BUSIO_USE_FAST_PINIO
BusIO_PortReg *mosiPort, *clkPort, *misoPort, *csPort;
BusIO_PortMask mosiPinMask, misoPinMask, clkPinMask, csPinMask;
#endif
bool _begun;
};

#endif // has SPI defined
Expand Down

0 comments on commit a97c62a

Please sign in to comment.