From 7cf4b57bc614683cf1a2ef9fa8d0b6647c97312e Mon Sep 17 00:00:00 2001 From: Steve Lascos Date: Fri, 19 Jan 2018 12:19:58 -0500 Subject: [PATCH] cleanup up LibMemoryManagement.* --- src/AudioEffectAnalogDelay.cpp | 14 ++- src/BAAudioControlWM8731.h | 6 +- src/BASpiMemory.h | 2 +- src/LibBasicFunctions.cpp | 49 ++++++--- src/LibMemoryManagement.cpp | 151 +++++++++++++++----------- src/LibMemoryManagement.h | 189 ++++++++++++++++++++++++++------- 6 files changed, 288 insertions(+), 123 deletions(-) diff --git a/src/AudioEffectAnalogDelay.cpp b/src/AudioEffectAnalogDelay.cpp index 97e2bfb..e08ecf7 100644 --- a/src/AudioEffectAnalogDelay.cpp +++ b/src/AudioEffectAnalogDelay.cpp @@ -71,7 +71,7 @@ void AudioEffectAnalogDelay::update(void) m_callCount++; Serial.println(String("AudioEffectAnalgDelay::update: ") + m_callCount); - m_memory->getSlot()->printStatus(); + //m_memory->getSlot()->printStatus(); audio_block_t *blockToRelease = m_memory->addBlock(inputAudioBlock); // if (inputAudioBlock) { @@ -113,7 +113,7 @@ void AudioEffectAnalogDelay::update(void) if (!blockToOutput) continue; // skip this channel due to failure // copy over data m_memory->getSamples(blockToOutput, m_channelOffsets[channel]); - //m_memory->read16(blockToOutput->data, 0, m_channelOffsets[channel], AUDIO_BLOCK_SAMPLES); + transmit(blockToOutput); release(blockToOutput); } @@ -126,6 +126,8 @@ bool AudioEffectAnalogDelay::delay(unsigned channel, float milliseconds) size_t delaySamples = calcAudioSamples(milliseconds); + if (!m_memory) { Serial.println("delay(): m_memory is not valid"); } + if (!m_externalMemory) { // internal memory QueuePosition queuePosition = calcQueuePosition(milliseconds); @@ -134,10 +136,11 @@ bool AudioEffectAnalogDelay::delay(unsigned channel, float milliseconds) // external memory Serial.println(String("CONFIG: delay:") + delaySamples); ExtMemSlot *slot = m_memory->getSlot(); + + if (!slot) { Serial.println("ERROR: slot ptr is not valid"); } if (!slot->isEnabled()) { slot->enable(); - } else { - Serial.println("ERROR: slot ptr is not valid"); + Serial.println("WEIRD: slot was not enabled"); } } @@ -151,12 +154,15 @@ bool AudioEffectAnalogDelay::delay(unsigned channel, size_t delaySamples) if (channel > MAX_DELAY_CHANNELS-1) // channel id too high return false; + if (!m_memory) { Serial.println("delay(): m_memory is not valid"); } + if (!m_externalMemory) { // internal memory QueuePosition queuePosition = calcQueuePosition(delaySamples); Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset); } else { // external memory + Serial.println(String("CONFIG: delay:") + delaySamples); ExtMemSlot *slot = m_memory->getSlot(); if (!slot->isEnabled()) { slot->enable(); diff --git a/src/BAAudioControlWM8731.h b/src/BAAudioControlWM8731.h index af00261..7d930c5 100644 --- a/src/BAAudioControlWM8731.h +++ b/src/BAAudioControlWM8731.h @@ -22,8 +22,8 @@ * along with this program. If not, see . *****************************************************************************/ -#ifndef __INC_BAAUDIOCONTROLWM8731_H -#define __INC_BAAUDIOCONTROLWM8731_H +#ifndef __BAAUDIOCONTROLWM8731_H +#define __BAAUDIOCONTROLWM8731_H namespace BAGuitar { @@ -128,4 +128,4 @@ private: } /* namespace BAGuitar */ -#endif /* __INC_BAAUDIOCONTROLWM8731_H */ +#endif /* __BAAUDIOCONTROLWM8731_H */ diff --git a/src/BASpiMemory.h b/src/BASpiMemory.h index efc2acc..2f2a765 100644 --- a/src/BASpiMemory.h +++ b/src/BASpiMemory.h @@ -59,7 +59,7 @@ public: void write16(size_t address, uint16_t data); void write16(size_t address, uint16_t *data, size_t numWords); - void zero16(size_t address, size_t numBytes); + void zero16(size_t address, size_t numWords); /// read a single 8-bit data word from the specified address /// @param address the address in the SPI RAM to read from diff --git a/src/LibBasicFunctions.cpp b/src/LibBasicFunctions.cpp index e78049a..1272703 100644 --- a/src/LibBasicFunctions.cpp +++ b/src/LibBasicFunctions.cpp @@ -50,9 +50,10 @@ AudioDelay::AudioDelay(float maxDelayTimeMs) } AudioDelay::AudioDelay(ExtMemSlot *slot) -: m_slot(slot) +//: m_slot(slot) { m_type = MemType::MEM_EXTERNAL; + m_slot = slot; } AudioDelay::~AudioDelay() @@ -77,15 +78,24 @@ audio_block_t* AudioDelay::addBlock(audio_block_t *block) return blockToRelease; } else { // EXTERNAL memory + if (!m_slot) { Serial.println("addBlock(): m_slot is not valid"); } - //m_slot->writeAdvance16(block->data, AUDIO_BLOCK_SAMPLES); + if (block) { + + // Audio is stored in reverse in block so we need to write it backwards to external memory + // to maintain temporal coherency. +// int16_t *srcPtr = block->data + AUDIO_BLOCK_SAMPLES - 1; +// for (int i=0; iwriteAdvance16(*srcPtr); +// srcPtr--; +// } + + int16_t *srcPtr = block->data; + for (int i=0; iwriteAdvance16(*srcPtr); + srcPtr++; + } - // Audio is stored in reverse in block so we need to write it backwards to external memory - // to maintain temporal coherency. - int16_t *srcPtr = block->data + AUDIO_BLOCK_SAMPLES - 1; - for (int i=0; iwriteAdvance16(*srcPtr); - srcPtr--; } return block; @@ -140,25 +150,36 @@ bool AudioDelay::getSamples(audio_block_t *dest, size_t offset, size_t numSample } else { // EXTERNAL Memory - if (numSamples <= m_slot->size() ) { - int currentPosition = (int)m_slot->getWritePosition() - (int)AUDIO_BLOCK_SAMPLES; + if (numSamples*sizeof(int16_t) <= m_slot->size() ) { + int currentPositionBytes = (int)m_slot->getWritePosition() - (int)(AUDIO_BLOCK_SAMPLES*sizeof(int16_t)); + size_t offsetBytes = offset * sizeof(int16_t); - if ((int)offset <= currentPosition) { - m_slot->setReadPosition(currentPosition - offset); + if ((int)offsetBytes <= currentPositionBytes) { + m_slot->setReadPosition(currentPositionBytes - offsetBytes); } else { // It's going to wrap around to the end of the slot - int readPosition = (int)m_slot->size() + currentPosition - offset; + int readPosition = (int)m_slot->size() + currentPositionBytes - offsetBytes; m_slot->setReadPosition((size_t)readPosition); } + m_slot->printStatus(); + // write the data to the destination block in reverse - int16_t *destPtr = dest->data + AUDIO_BLOCK_SAMPLES-1; +// int16_t *destPtr = dest->data + AUDIO_BLOCK_SAMPLES-1; +// for (int i=0; ireadAdvance16(); +// destPtr--; +// } + + int16_t *destPtr = dest->data; for (int i=0; ireadAdvance16(); + destPtr++; } return true; } else { // numSampmles is > than total slot size + Serial.println("getSamples(): ERROR numSamples > total slot size"); return false; } } diff --git a/src/LibMemoryManagement.cpp b/src/LibMemoryManagement.cpp index 9f413b1..9927121 100644 --- a/src/LibMemoryManagement.cpp +++ b/src/LibMemoryManagement.cpp @@ -1,9 +1,26 @@ - +/* + * LibMemoryManagement.cpp + * + * Created on: Jan 19, 2018 + * Author: slascos + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version.* + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ #include #include #include "Audio.h" - #include "LibMemoryManagement.h" namespace BAGuitar { @@ -19,12 +36,21 @@ bool ExtMemSlot::clear() return true; } -bool ExtMemSlot::write16(size_t offset, int16_t *dataPtr, size_t dataSize) +bool ExtMemSlot::setWritePosition(size_t offsetBytes) +{ + if (m_start + offsetBytes <= m_end) { + m_currentWrPosition = m_start + offsetBytes; + return true; + } else { return false; } +} + +bool ExtMemSlot::write16(size_t offsetBytes, int16_t *dest, size_t numWords) { if (!m_valid) { return false; } - size_t writeStart = m_start + offset; - if ((writeStart + dataSize-1) <= m_end) { - m_spi->write16(writeStart, reinterpret_cast(dataPtr), dataSize); // cast audio data to uint + size_t writeStart = m_start + offsetBytes; // 2x because int16 is two bytes per data + size_t numBytes = sizeof(int16_t)*numWords; + if ((writeStart + numBytes-1) <= m_end) { + m_spi->write16(writeStart, reinterpret_cast(dest), numWords); // cast audio data to uint return true; } else { // this would go past the end of the memory slot, do not perform the write @@ -32,12 +58,23 @@ bool ExtMemSlot::write16(size_t offset, int16_t *dataPtr, size_t dataSize) } } -bool ExtMemSlot::zero16(size_t offset, size_t dataSize) +bool ExtMemSlot::setReadPosition(size_t offsetBytes) +{ + if (m_start + offsetBytes <= m_end) { + m_currentRdPosition = m_start + offsetBytes; + return true; + } else { + return false; + } +} + +bool ExtMemSlot::zero16(size_t offsetBytes, size_t numWords) { if (!m_valid) { return false; } - size_t writeStart = m_start + offset; - if ((writeStart + dataSize-1) <= m_end) { - m_spi->zero16(writeStart, dataSize); // cast audio data to uint + size_t writeStart = m_start + offsetBytes; + size_t numBytes = sizeof(int16_t)*numWords; + if ((writeStart + numBytes-1) <= m_end) { + m_spi->zero16(writeStart, numWords); // cast audio data to uint return true; } else { // this would go past the end of the memory slot, do not perform the write @@ -45,16 +82,17 @@ bool ExtMemSlot::zero16(size_t offset, size_t dataSize) } } -bool ExtMemSlot::read16(int16_t *dest, size_t srcOffset, size_t numData) +bool ExtMemSlot::read16(int16_t *dest, size_t offsetBytes, size_t numWords) { if (!dest) return false; // invalid destination - size_t readOffset = m_start + srcOffset; + size_t readOffset = m_start + offsetBytes; + size_t numBytes = sizeof(int16_t)*numWords; - if ((readOffset + (numData*sizeof(int16_t))-1) <= m_end) { - m_spi->read16(readOffset, reinterpret_cast(dest), numData); + if ((readOffset + numBytes-1) <= m_end) { + m_spi->read16(readOffset, reinterpret_cast(dest), numWords); return true; } else { - // this would go past the end of the memory slot, do not perform the write + // this would go past the end of the memory slot, do not perform the read return false; } } @@ -62,8 +100,8 @@ bool ExtMemSlot::read16(int16_t *dest, size_t srcOffset, size_t numData) uint16_t ExtMemSlot::readAdvance16() { uint16_t val = m_spi->read16(m_currentRdPosition); - if (m_currentRdPosition < m_end) { - m_currentRdPosition++; + if (m_currentRdPosition < m_end-1) { + m_currentRdPosition +=2; // position is in bytes and we read two } else { m_currentRdPosition = m_start; } @@ -71,70 +109,65 @@ uint16_t ExtMemSlot::readAdvance16() } -//void ExtMemSlot::read16FromPast(int16_t *dest, size_t currentOffset, size_t numData) -//{ -// size_t readStart; -// if (m_currentPosition - currentOffset >= m_start) { -// readStart = m_currentPosition - currentOffset; -// } else { -// // this offset will wrap the memory slot -// size_t numBytesToStart = m_currentPosition; -// readStart = m_end - (currentOffset - numBytesToStart); -// } -// m_spi->read16(readStart, reinterpret_cast(dest), numData); -//} - -bool ExtMemSlot::writeAdvance16(int16_t *dataPtr, size_t dataSize) +bool ExtMemSlot::writeAdvance16(int16_t *src, size_t numWords) { if (!m_valid) { return false; } - if (m_currentWrPosition + dataSize-1 <= m_end) { + size_t numBytes = sizeof(int16_t)*numWords; + + if (m_currentWrPosition + numBytes-1 <= m_end) { // entire block fits in memory slot without wrapping - m_spi->write16(m_currentWrPosition, reinterpret_cast(dataPtr), dataSize); // cast audio data to uint. - m_currentWrPosition += dataSize; + m_spi->write16(m_currentWrPosition, reinterpret_cast(src), numWords); // cast audio data to uint. + m_currentWrPosition += numBytes; } else { // this write will wrap the memory slot - size_t numBytes = m_end - m_currentWrPosition + 1; - m_spi->write16(m_currentWrPosition, reinterpret_cast(dataPtr), numBytes); - size_t remainingBytes = dataSize - numBytes; // calculate the remaining bytes - m_spi->write16(m_start, reinterpret_cast(dataPtr + numBytes), remainingBytes); // write remaining bytes are start - m_currentWrPosition = m_start + remainingBytes; + size_t wrBytes = m_end - m_currentWrPosition + 1; + size_t wrDataNum = wrBytes >> 1; // divide by two to get the number of data + m_spi->write16(m_currentWrPosition, reinterpret_cast(src), wrDataNum); + size_t remainingData = numWords - wrDataNum; + m_spi->write16(m_start, reinterpret_cast(src + wrDataNum), remainingData); // write remaining bytes are start + m_currentWrPosition = m_start + (remainingData*sizeof(int16_t)); } return true; } -bool ExtMemSlot::writeAdvance16(int16_t data) + +bool ExtMemSlot::zeroAdvance16(size_t numWords) { if (!m_valid) { return false; } + size_t numBytes = 2*numWords; + if (m_currentWrPosition + numBytes-1 <= m_end) { + // entire block fits in memory slot without wrapping + m_spi->zero16(m_currentWrPosition, numWords); // cast audio data to uint. + m_currentWrPosition += numBytes; - m_spi->write16(m_currentWrPosition, static_cast(data)); - if (m_currentWrPosition < m_end) { - m_currentWrPosition++; } else { - m_currentWrPosition = m_start; + // this write will wrap the memory slot + size_t wrBytes = m_end - m_currentWrPosition + 1; + size_t wrDataNum = wrBytes >> 1; + m_spi->zero16(m_currentWrPosition, wrDataNum); + size_t remainingWords = numWords - wrDataNum; // calculate the remaining bytes + m_spi->zero16(m_start, remainingWords); // write remaining bytes are start + m_currentWrPosition = m_start + remainingWords*sizeof(int16_t); } return true; } -bool ExtMemSlot::zeroAdvance16(size_t dataSize) + +bool ExtMemSlot::writeAdvance16(int16_t data) { if (!m_valid) { return false; } - if (m_currentWrPosition + dataSize-1 <= m_end) { - // entire block fits in memory slot without wrapping - m_spi->zero16(m_currentWrPosition, dataSize); // cast audio data to uint. - m_currentWrPosition += dataSize; + m_spi->write16(m_currentWrPosition, static_cast(data)); + if (m_currentWrPosition < m_end-1) { + m_currentWrPosition+=2; // wrote two bytes } else { - // this write will wrap the memory slot - size_t numBytes = m_end - m_currentWrPosition + 1; - m_spi->zero16(m_currentWrPosition, numBytes); - size_t remainingBytes = dataSize - numBytes; // calculate the remaining bytes - m_spi->zero16(m_start, remainingBytes); // write remaining bytes are start - m_currentWrPosition = m_start + remainingBytes; + m_currentWrPosition = m_start; } return true; } + bool ExtMemSlot::enable() const { if (m_spi) { @@ -158,6 +191,7 @@ void ExtMemSlot::printStatus(void) const { Serial.println(String("valid:") + m_valid + String(" m_start:") + m_start + \ String(" m_end:") + m_end + String(" m_currentWrPosition: ") + m_currentWrPosition + \ + String(" m_currentRdPosition: ") + m_currentRdPosition + \ String(" m_size:") + m_size); } @@ -178,11 +212,6 @@ ExternalSramManager::ExternalSramManager(unsigned numMemories) m_memConfig[i].nextAvailable = 0; m_memConfig[i].m_spi = nullptr; -// if (i < numMemories) { -// m_memConfig[i].m_spi = new BAGuitar::BASpiMemory(static_cast(i)); -// } else { -// m_memConfig[i].m_spi = nullptr; -// } } m_configured = true; } @@ -204,7 +233,7 @@ bool ExternalSramManager::requestMemory(ExtMemSlot *slot, float delayMillisecond { // convert the time to numer of samples size_t delayLengthInt = (size_t)((delayMilliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f); - return requestMemory(slot, delayLengthInt, mem); + return requestMemory(slot, delayLengthInt * sizeof(int16_t), mem); } bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem) diff --git a/src/LibMemoryManagement.h b/src/LibMemoryManagement.h index 9fedbc8..e4e44c8 100644 --- a/src/LibMemoryManagement.h +++ b/src/LibMemoryManagement.h @@ -1,87 +1,196 @@ -/* - * ExtMemoryManagement.h +/**************************************************************************//** + * @file + * @author Steve Lascos + * @company Blackaddr Audio * - * Created on: Dec 23, 2017 - * Author: slascos - */ + * LibMemoryManagment is a class for providing access to external SPI based + * SRAM with the optional convience of breaking it up into 'slots' which are smaller + * memory entities. + * @details This class treats an external memory as a pool from which the user requests + * a block. When using that block, the user need not be concerned with where the pool + * it came from, they only deal with offsets from the start of their memory block. Ie. + * Your particular slot of memory appears to you to start at 0 and end at whatever size + * was requested. + * + * @copyright This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version.* + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ -#ifndef SRC_LIBMEMORYMANAGEMENT_H_ -#define SRC_LIBMEMORYMANAGEMENT_H_ +#ifndef __LIBMEMORYMANAGEMENT_H +#define __LIBMEMORYMANAGEMENT_H #include - -//#include "Audio.h" - #include "BAHardware.h" #include "BASpiMemory.h" -//#include "LibBasicFunctions.h" namespace BAGuitar { +/**************************************************************************//** + * MemConfig contains the configuration information associated with a particular + * SPI interface. + *****************************************************************************/ struct MemConfig { - size_t size; - size_t totalAvailable; - size_t nextAvailable; - BASpiMemory *m_spi = nullptr; + size_t size; ///< the total size of the external SPI memory + size_t totalAvailable; ///< the number of bytes available (remaining) + size_t nextAvailable; ///< the starting point for the next available slot + BASpiMemory *m_spi = nullptr; ///< handle to the SPI interface }; -class ExternalSramManager; // forward declare so ExtMemSlot can setup friendship +class ExternalSramManager; // forward declare so ExtMemSlot can declared friendship with it +/**************************************************************************//** + * ExtMemSlot provides a convenient interface to a particular slot of an + * external memory. + * @details the memory can be access randomly, as a single word, as a block of + * data, or as circular queue. + *****************************************************************************/ class ExtMemSlot { public: + /// clear the entire contents of the slot by writing zeros + /// @returns true on success bool clear(); - bool setWritePosition(size_t offset) { m_currentWrPosition = m_start + offset; return true;} // TODO add range check + + /// set a new write position (in bytes) for circular operation + /// @param offsetBytes moves the write pointer to the specified offset from the slot start + /// @returns true on success, else false if offset is beyond slot boundaries. + bool setWritePosition(size_t offsetBytes); + + /// returns the currently set write pointer pointer + /// @returns the write position value size_t getWritePosition() const { return m_currentWrPosition-m_start; } - bool setReadPosition(size_t offset) { m_currentRdPosition = m_start + offset; return true;} // TODO add range check - size_t getReadPosition() const { return m_currentRdPosition-m_start; } + /// set a new read position (in bytes) for circular operation + /// @param offsetBytes moves the read pointer to the specified offset from the slot start + /// @returns true on success, else false if offset is beyond slot boundaries. + bool setReadPosition(size_t offsetBytes); - bool write16(size_t offset, int16_t *dataPtr, size_t numData); - bool zero16(size_t offset, size_t numData); - bool read16(int16_t *dest, size_t srcOffset, size_t numData); + /// returns the currently set read pointer pointer + /// @returns the read position value + size_t getReadPosition() const { return m_currentRdPosition-m_start; } + /// Write a block of 16-bit data to the memory at the specified offset + /// @param offsetBytes offset in bytes from start of slot + /// @param dataPtr pointer to start of block of 16-bit data + /// @param numWords number of 16-bit words to transfer + /// @returns true on success, else false on error + bool write16(size_t offsetBytes, int16_t *dest, size_t numWords); + + /// Write a block of zeros (16-bit) to the memory at the specified offset + /// @param offsetBytes offset in bytes from start of slot + /// @param numWords number of 16-bit words to transfer + /// @returns true on success, else false on error + bool zero16(size_t offsetBytes, size_t numWords); + + /// Read a block of 16-bit data from the memory at the specified location + /// @param dest pointer to destination for the read data + /// @param offsetBytes offset in bytes from start of slot + /// @param numWords number of 16-bit words to transfer + /// @returns true on success, else false on error + bool read16(int16_t *dest, size_t offsetBytes, size_t numWords); + + /// Read the next in memory during circular operation + /// @returns the next 16-bit data word in memory uint16_t readAdvance16(); - bool writeAdvance16(int16_t *dataPtr, size_t numData); + + /// Write a block of 16-bit data from the specified location in circular operation + /// @param src pointer to the start of the block of data to write to memory + /// @param numWords number of 16-bit words to transfer + /// @returns true on success, else false on error + bool writeAdvance16(int16_t *src, size_t numWords); + + /// Write a single 16-bit data to the next location in circular operation + /// @param data the 16-bit word to transfer + /// @returns true on success, else false on error bool writeAdvance16(int16_t data); // write just one data - bool zeroAdvance16(size_t numData); - //void read16FromPast(int16_t *dest, size_t Offset, size_t numData); + + /// Write a block of 16-bit data zeros in circular operation + /// @param numWords number of 16-bit words to transfer + /// @returns true on success, else false on error + bool zeroAdvance16(size_t numWords); + + + /// Get the size of the memory slot + /// @returns size of the slot in bytes size_t size() const { return m_size; } + + /// Ensures the underlying SPI interface is enabled + /// @returns true on success, false on error bool enable() const; + + /// Checks whether underlying SPI interface is enabled + /// @returns true if enabled, false if not enabled bool isEnabled() const; + + /// DEBUG USE: prints out the slot member variables void printStatus(void) const; private: - friend ExternalSramManager; - bool m_valid = false; - size_t m_start = 0; - size_t m_end = 0; - size_t m_currentWrPosition = 0; - size_t m_currentRdPosition = 0; - size_t m_size = 0; - SpiDeviceId m_spiId; - BASpiMemory *m_spi = nullptr; + friend ExternalSramManager; ///< gives the manager access to the private variables + bool m_valid = false; ///< After a slot is successfully configured by the manager it becomes valid + size_t m_start = 0; ///< the external memory address in bytes where this slot starts + size_t m_end = 0; ///< the external memory address in bytes where this slot ends (inclusive) + size_t m_currentWrPosition = 0; ///< current write pointer for circular operation + size_t m_currentRdPosition = 0; ///< current read pointer for circular operation + size_t m_size = 0; ///< size of this slot in bytes + SpiDeviceId m_spiId; ///< the SPI Device ID + BASpiMemory *m_spi = nullptr; ///< pointer to an instance of the BASpiMemory interface class }; +/**************************************************************************//** + * ExternalSramManager provides a class to handle dividing an external SPI RAM + * into independent slots for general use. + * @details the class does not support deallocated memory because this would cause + * fragmentation. + *****************************************************************************/ class ExternalSramManager final { public: ExternalSramManager() = delete; - ExternalSramManager(unsigned numMemories); + + /// The manager is constructed by specifying how many external memories to handle allocations for + /// @param numMemories the number of external memories + ExternalSramManager(unsigned numMemories = 1); virtual ~ExternalSramManager(); - size_t availableMemory(BAGuitar::MemSelect mem); + /// Query the amount of available (unallocated) memory + /// @details note that currently, memory cannot be allocated. + /// @param mem specifies which memory to query, default is memory 0 + /// @returns the available memory in bytes + size_t availableMemory(BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0); + + /// Request memory be allocated for the provided slot + /// @param slot a pointer to the global slot object to which memory will be allocated + /// @param delayMilliseconds request the amount of memory based on required time for audio samples, rather than number of bytes. + /// @param mem specify which external memory to allocate from + /// @returns true on success, otherwise false on error bool requestMemory(ExtMemSlot *slot, float delayMilliseconds, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0); - bool requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0); + + /// Request memory be allocated for the provided slot + /// @param slot a pointer to the global slot object to which memory will be allocated + /// @param sizeBytes request the amount of memory in bytes to request + /// @param mem specify which external memory to allocate from + /// @returns true on success, otherwise false on error + bool requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0); private: - static bool m_configured; - static MemConfig m_memConfig[BAGuitar::NUM_MEM_SLOTS]; + static bool m_configured; ///< there should only be one instance of ExternalSramManager in the whole project + static MemConfig m_memConfig[BAGuitar::NUM_MEM_SLOTS]; ///< store the configuration information for each external memory }; } -#endif /* SRC_LIBMEMORYMANAGEMENT_H_ */ +#endif /* __LIBMEMORYMANAGEMENT_H */