diff --git a/src/shared/drivers/dma/DMA.cpp b/src/shared/drivers/dma/DMA.cpp index 1a60eeabbcf1f6a4fa38ae781a102a8f48eca1ec..5edfcec61870ccd4a4eb55c962e596592195c2ea 100644 --- a/src/shared/drivers/dma/DMA.cpp +++ b/src/shared/drivers/dma/DMA.cpp @@ -307,14 +307,30 @@ bool DMADriver::tryChannel(DMADefs::DMAStreamId id) return streams.count(id) == 0; } -DMAStream* DMADriver::acquireStream(DMADefs::DMAStreamId id, - DMADefs::Channel channel) +DMAStream* DMADriver::acquireStreamBlocking( + DMADefs::DMAStreamId id, DMADefs::Channel channel, + const std::chrono::nanoseconds timeout) { Lock<FastMutex> l(mutex); - // Wait until the channel is free + // Wait until the stream is free or the timeout expires while (streams.count(id) != 0) - cv.wait(l); + { + if (timeout == std::chrono::nanoseconds::zero()) + { + cv.wait(l); + } + else + { + auto res = cv.timedWait(l, timeout.count()); + + if (res == TimedWaitResult::Timeout) + { + // The timeout expired + return nullptr; + } + } + } // Enable the clock if not already done // TODO: Enable DMA1 or DMA2 @@ -324,27 +340,45 @@ DMAStream* DMADriver::acquireStream(DMADefs::DMAStreamId id, return streams[id] = new DMAStream(id, channel); } -DMAStream* DMADriver::automaticAcquireStream(DMADefs::Peripherals peripheral) +DMAStream* DMADriver::automaticAcquireStreamBlocking( + DMADefs::Peripherals peripheral, const std::chrono::nanoseconds timeout) { - auto availableStreams = DMADefs::mapPeripherals.equal_range(peripheral); + const auto availableStreams = + DMADefs::mapPeripherals.equal_range(peripheral); - // Iterate through the streams for that peripheral, - // return the first available Lock<FastMutex> l(mutex); - for (auto it = availableStreams.first; it != availableStreams.second; ++it) + while (true) { - DMADefs::DMAStreamId id = it->second.first; - DMADefs::Channel channel = it->second.second; + // Iterate through the streams for that peripheral, + // return the first available + for (auto it = availableStreams.first; it != availableStreams.second; + ++it) + { + DMADefs::DMAStreamId id = it->second.first; + DMADefs::Channel channel = it->second.second; + + if (streams.count(id) == 0) + { + // Stream is free + return streams[id] = new DMAStream(id, channel); + } + } - if (streams.count(id) == 0) + if (timeout == std::chrono::nanoseconds::zero()) { - // Stream is free - return streams[id] = new DMAStream(id, channel); + cv.wait(l); } - } + else + { + auto res = cv.timedWait(l, timeout.count()); - // TODO: improve error handling - return nullptr; + if (res == TimedWaitResult::Timeout) + { + // The timeout expired + return nullptr; + } + } + } } void DMADriver::releaseStream(DMADefs::DMAStreamId id) diff --git a/src/shared/drivers/dma/DMA.h b/src/shared/drivers/dma/DMA.h index e94b49ea7d3c5f58c7e9aa34c86effe89cda4d35..3bb976f0f48391b4631fdd6e1ff1f59cfc462a9b 100644 --- a/src/shared/drivers/dma/DMA.h +++ b/src/shared/drivers/dma/DMA.h @@ -99,10 +99,34 @@ public: bool tryChannel(DMADefs::DMAStreamId id); - DMAStream* acquireStream(DMADefs::DMAStreamId id, DMADefs::Channel channel); + /** + * @brief Try to acquire the specified stream and initialize it with the + * correct channel. + * @param id The id of the stream to be acquired. + * @param channel The channel used to initialize the stream. + * @param timeout The maximum time that will be waited when in blocking + * mode, 0 to disable the timeout and wait forever. + * @return The pointer to the allocated stream if successful, nullptr if the + * timeout expired. + */ + DMAStream* acquireStreamBlocking(DMADefs::DMAStreamId id, + DMADefs::Channel channel, + const std::chrono::nanoseconds timeout); - // TODO: change name - DMAStream* automaticAcquireStream(DMADefs::Peripherals peripheral); + /** + * @brief Try to acquire a stream that is connected to the specified + * peripheral. + * @param peripheral The wanted peripheral. + * @param timeout The maximum time that will be waited when in blocking + * mode, 0 to disable the timeout and wait forever. + * @return The pointer to the allocated stream if successful, nullptr if the + * timeout expired. + * + * TODO: change name + */ + DMAStream* automaticAcquireStreamBlocking( + DMADefs::Peripherals peripheral, + const std::chrono::nanoseconds timeout); void releaseStream(DMADefs::DMAStreamId id); diff --git a/src/tests/drivers/test-dma-mem-to-mem.cpp b/src/tests/drivers/test-dma-mem-to-mem.cpp index aa53a2b7fce11090e443c9334add7deaf617e713..d4970559df83786494acea4fdc851c308bff158b 100644 --- a/src/tests/drivers/test-dma-mem-to-mem.cpp +++ b/src/tests/drivers/test-dma-mem-to-mem.cpp @@ -33,11 +33,8 @@ void printBuffer(uint8_t *buffer, size_t size); int main() { - // DMAStream* stream = - // DMADriver::instance().acquireStream(DMADefs::DMAStreamId::DMA2_Str0, - // DMADefs::Channel::CHANNEL0); - DMAStream *stream = DMADriver::instance().automaticAcquireStream( - DMADefs::Peripherals::PE_MEM_ONLY); + DMAStream *stream = DMADriver::instance().automaticAcquireStreamBlocking( + DMADefs::Peripherals::PE_MEM_ONLY, std::chrono::seconds::zero()); if (stream == nullptr) {