diff --git a/components/f4ll/.gitignore b/components/f4ll/.gitignore new file mode 100644 index 0000000..c570f57 --- /dev/null +++ b/components/f4ll/.gitignore @@ -0,0 +1,4 @@ +CMakeFiles/ +CMakeCache.txt +build.ninja +cmake_install.cmake \ No newline at end of file diff --git a/components/f4ll/.gitrepo b/components/f4ll/.gitrepo index 07c77e9..7046842 100644 --- a/components/f4ll/.gitrepo +++ b/components/f4ll/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = ssh://git@codeberg.org/abody/f4ll.git branch = master - commit = a4c1baa4109ed591c9db556da430fadfac0642a6 - parent = 4e1f01c4d45a06b03c631b229402f8c625900922 + commit = f86c164de5c279c378c5cde408af5fe75497c474 + parent = d72d3af2a7e99af89780fcfa66071f99db11c766 method = merge cmdver = 0.4.9 diff --git a/components/f4ll/CMakeLists.txt b/components/f4ll/CMakeLists.txt index 0664851..1236174 100644 --- a/components/f4ll/CMakeLists.txt +++ b/components/f4ll/CMakeLists.txt @@ -1,3 +1,5 @@ +cmake_minimum_required(VERSION 3.22) + add_library(f4ll STATIC src/console_handler.cpp src/crc_handler.cpp @@ -5,6 +7,7 @@ add_library(f4ll STATIC src/fault.cpp src/memcpy_dma.cpp src/packet_usart.cpp + src/ringbuffer.cpp src/str_util.cpp src/usart_core.cpp ) diff --git a/components/f4ll/inc/f4ll/console_handler.h b/components/f4ll/inc/f4ll/console_handler.h index 27a2a7e..210e410 100644 --- a/components/f4ll/inc/f4ll/console_handler.h +++ b/components/f4ll/inc/f4ll/console_handler.h @@ -8,8 +8,10 @@ #pragma once #include -#include #include +#include + +#include namespace f4ll { @@ -18,12 +20,26 @@ class console_handler : public usart_core, public initialized_singleton; public: + using size_type = iringbuffer::size_type; + + class iconsole_input + { + public: + virtual void input_available(size_type len) = 0; + }; + void print(char const *s); void flush(); - size_t append(char const *s); + size_type append(char const *s); + + iringbuffer &get_rx_buffer() { return m_rx_buffer; } private: - console_handler(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx); + console_handler( + USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx, uint8_t *rx_buffer, size_type x_buffer_size, + uint8_t *tx_buffer, size_type tx_buffer_size, iconsole_input *rx_callback); + + void setup_receive(void); // LL_UsartCore pure virtual function implementations virtual void receiver_idle(void) override; @@ -37,8 +53,13 @@ private: virtual void tx_dma_half_transfer(void) override; virtual void tx_dma_error(dma_helper::dma_error_type reason) override; - ringbuffer<128> m_tx_buffer; - iringbuffer::size_type m_in_flight_size = 0; + ringbuffer_ext m_tx_buffer; + size_type m_bytes_sent = 0; + + ringbuffer_ext m_rx_buffer; + size_type m_bytes_requested = 0; + size_type m_reqd_bytes_registered = 0; + iconsole_input *m_rx_callback; }; } /* namespace f4ll */ diff --git a/components/f4ll/inc/f4ll/crc_handler.h b/components/f4ll/inc/f4ll/crc_handler.h index 8fb6b27..26ae056 100644 --- a/components/f4ll/inc/f4ll/crc_handler.h +++ b/components/f4ll/inc/f4ll/crc_handler.h @@ -6,10 +6,12 @@ */ #pragma once +#include + +#include + #include #include -#include -#include namespace f4ll { diff --git a/components/f4ll/inc/f4ll/dma_helper.h b/components/f4ll/inc/f4ll/dma_helper.h index 82347e7..b2d1045 100644 --- a/components/f4ll/inc/f4ll/dma_helper.h +++ b/components/f4ll/inc/f4ll/dma_helper.h @@ -8,6 +8,7 @@ #pragma once #include + #include namespace f4ll { @@ -38,9 +39,9 @@ public: private: DMA_TypeDef *m_dma; - uint32_t m_stream; - volatile uint32_t *m_is_reg; - volatile uint32_t *m_ifc_reg; + uint32_t const m_stream; + volatile uint32_t * const m_is_reg; + volatile uint32_t * const m_ifc_reg; static constexpr uint32_t const m_fe_masks[8] = {DMA_LISR_FEIF0, DMA_LISR_FEIF1, DMA_LISR_FEIF2, DMA_LISR_FEIF3, DMA_HISR_FEIF4, DMA_HISR_FEIF5, DMA_HISR_FEIF6, DMA_HISR_FEIF7}; diff --git a/components/f4ll/inc/f4ll/memcpy_dma.h b/components/f4ll/inc/f4ll/memcpy_dma.h index 4fcd299..ab728d1 100644 --- a/components/f4ll/inc/f4ll/memcpy_dma.h +++ b/components/f4ll/inc/f4ll/memcpy_dma.h @@ -6,6 +6,8 @@ */ #pragma once +#include + #include #include diff --git a/components/f4ll/inc/f4ll/ringbuffer.h b/components/f4ll/inc/f4ll/ringbuffer.h index acf39d1..c2dc08d 100644 --- a/components/f4ll/inc/f4ll/ringbuffer.h +++ b/components/f4ll/inc/f4ll/ringbuffer.h @@ -9,7 +9,6 @@ #include #include -#include namespace f4ll { @@ -35,22 +34,30 @@ public: /// without registering the consumption. /// The caller should also call report_consumption using the returned /// chunk length after it finished processing the data. - /// @param[in] len_requested Length of the data requested from the buffer. - /// The length of the actual data provided - /// might be actually smaller (because either reaching the end of - /// the buffer or not enough data in the buffer). /// @param[out] data Receives a pointer to the first byte of the available /// data in the buffer /// @param[out] len Receives the length of the chunk available in the buffer. /// Will not exceed len_requested. /// @retval true if the buffer has more available data, false otherwise. - virtual bool get_chunk(size_type len_requested, uint8_t const *&data, size_type &len) const = 0; + virtual bool get_chunk(uint8_t const *&data, size_type &len) const = 0; /// @brief Marks the chunk returned by ringbuffer_GetChunk as available. /// @param consumed The length of the chunk as returned by /// ringbuffer_GetChunk(..., len) virtual void consumed(size_type len) = 0; + /// @brief Gets a pointer to the next free chunk in the buffer + /// @retval Pointer to the beginning of the next free buffer chmemory area + /// @param[out] len Receives the length of the returned buffer area. + virtual uint8_t *get_free_chunk(size_type &len) = 0; + + /// @brief Registers the data written in the free buffer chunk. + /// IMPORTANT: Do not call put() after start modifying the buffer + /// returned by get_free_chunk() before registering the written data by + /// calling supplied() + /// @param len The length of the data written in the buffer + virtual bool produced(size_type len) = 0; + /// @brief Returns the number of uncommited bytes in the ring buffer. virtual size_type uncommited() const = 0; @@ -72,15 +79,21 @@ public: virtual size_type unused() const = 0; }; -template class ringbuffer : public iringbuffer +// +class ringbuffer_ext : public iringbuffer { public: - ringbuffer() = default; + ringbuffer_ext(uint8_t *bptr, size_type bsize); size_type put(uint8_t const *data, size_type len) override; void commit() override; - bool get_chunk(size_type len_requested, uint8_t const *&data, size_type &len) const override; + + bool get_chunk(uint8_t const *&data, size_type &len) const override; void consumed(size_type len) override; + + uint8_t *get_free_chunk(size_type &len) override; + bool produced(size_type len) override; + size_type uncommited() const override; size_type commited() const override; void discard() override; @@ -89,130 +102,32 @@ public: size_type unused() const override; private: - uint8_t m_buffer[SZ]; //!< Data bufer + uint8_t *m_buffer; //!< Data bufer + size_type const m_bsize; //!< Data buffer size size_type m_head = 0; //!< Write position size_type m_head_shadow = 0; //!< Shadowed write position for collecting data //!< before committing it size_type m_tail = 0; //!< Read position size_type marker_diff(size_type m1, size_type m2) const; + size_type max_chunk_len() const; }; // -template iringbuffer::size_type ringbuffer::put(uint8_t const *data, size_type len) +template class ringbuffer : public ringbuffer_ext { - size_type chunk1 = 0; - size_type chunk2 = 0; +public: + ringbuffer(); - if (!data || !len) { - return 0; - } - - size_type max_len = unused(); - len = len < max_len ? len : max_len; - - chunk1 = sizeof(m_buffer) - m_head_shadow; - if (chunk1 >= len) { - chunk1 = len; - } else { - chunk2 = len - chunk1; - } - - std::memcpy(m_buffer + m_head_shadow, data, chunk1); - m_head_shadow += chunk1; - if (m_head_shadow == sizeof(m_buffer)) { - m_head_shadow = 0; - } - - if (chunk2) { - std::memcpy(m_buffer, data + chunk1, chunk2); - m_head_shadow += chunk2; - if (m_head_shadow == sizeof(m_buffer)) { - m_head_shadow = 0; - } - } - - return len; -} - -template void ringbuffer::commit() -{ - m_head = m_head_shadow; +private: + uint8_t m_buffer[SZ]; }; -template bool ringbuffer::get_chunk(size_type len_requested, uint8_t const *&data, size_type &len) const +// +template +ringbuffer::ringbuffer() + : ringbuffer_ext(m_buffer, SZ) { - if (!len_requested) { - return false; - } - - size_type head = m_head; - size_type tail = m_tail; - size_type chunk_size = head >= tail ? head - tail : sizeof(m_buffer) - tail; - - if (!chunk_size) { - len = 0; - return false; - } - - if (chunk_size > len_requested) { - chunk_size = len_requested; - } - data = m_buffer + tail; - len = chunk_size; - - tail += chunk_size; - if (tail == sizeof(m_buffer)) { - tail = 0; - } - - return tail != head; } -template void ringbuffer::consumed(size_type len) -{ - if (!len) { - return; - } - m_tail += len; - if (m_tail == sizeof(m_buffer)) { - m_tail = 0; - } -} - -template iringbuffer::size_type ringbuffer::uncommited() const -{ - return marker_diff(m_head_shadow, m_head); -} - -template iringbuffer::size_type ringbuffer::commited() const -{ - return marker_diff(m_head, m_tail); -} - -template void ringbuffer::discard() -{ - m_head_shadow = m_head; -} - -template iringbuffer::size_type ringbuffer::size() const -{ - return SZ; -} - -template iringbuffer::size_type ringbuffer::used() const -{ - return marker_diff(m_head_shadow, m_tail); -} - -template iringbuffer::size_type ringbuffer::unused() const -{ - return SZ - used() - 1; -} - -template iringbuffer::size_type ringbuffer::marker_diff(size_type m1, size_type m2) const -{ - return (m1 >= m2) ? (m1 - m2) : (SZ - m2 + m1); -} - -} // namespace f1ll \ No newline at end of file +} // namespace f1ll diff --git a/components/f4ll/inc/f4ll/usart_core.h b/components/f4ll/inc/f4ll/usart_core.h index 508df34..fa17f2d 100644 --- a/components/f4ll/inc/f4ll/usart_core.h +++ b/components/f4ll/inc/f4ll/usart_core.h @@ -31,6 +31,7 @@ protected: dma_helper m_tx_dma; private: + // these functions are called from interrup context! virtual void receiver_idle(void) = 0; virtual void transmission_complete(void) = 0; virtual void framing_error(void) = 0; diff --git a/components/f4ll/src/console_handler.cpp b/components/f4ll/src/console_handler.cpp index a4ba4a6..e1955f1 100644 --- a/components/f4ll/src/console_handler.cpp +++ b/components/f4ll/src/console_handler.cpp @@ -6,31 +6,42 @@ */ #include -#include #include #include namespace f4ll { -console_handler::console_handler(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx) - : usart_core(usart, dma, stream_rx, stream_tx) +console_handler::console_handler( + USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx, uint8_t *rx_buffer, size_type rx_buffer_size, + uint8_t *tx_buffer, size_type tx_buffer_size, iconsole_input *rx_callback) + : usart_core(usart, dma, stream_rx, stream_tx), + m_tx_buffer(tx_buffer, tx_buffer_size), + m_rx_buffer(rx_buffer, rx_buffer_size), + m_rx_callback(rx_callback) { + LL_USART_EnableIT_IDLE(usart); + LL_USART_EnableIT_ERROR(usart); + setup_receive(); } -void console_handler::receiver_idle(void) {} - -void console_handler::transmission_complete(void) +void console_handler::setup_receive(void) { - m_tx_buffer.consumed(m_in_flight_size); - if (m_tx_buffer.commited()) { - uint8_t const *chunk; - m_tx_buffer.get_chunk(m_tx_buffer.size(), chunk, m_in_flight_size); - if (m_in_flight_size) { - setup_transmit(chunk, m_in_flight_size); + uint8_t *bptr = m_rx_buffer.get_free_chunk(m_bytes_requested); + m_reqd_bytes_registered = 0; + usart_core::setup_receive(bptr, m_bytes_requested); +} + +void console_handler::receiver_idle(void) +{ + uint16_t rcvd_bytes = m_bytes_requested - m_reqd_bytes_registered - LL_DMA_GetDataLength(m_rx_dma.get_dma(), m_rx_dma.get_stream()); + if (rcvd_bytes) { + m_reqd_bytes_registered += rcvd_bytes; + m_rx_buffer.produced(rcvd_bytes); + m_rx_buffer.commit(); + if (m_rx_callback) { + m_rx_callback->input_available(rcvd_bytes); } - } else { - m_in_flight_size = 0; } } @@ -38,7 +49,19 @@ void console_handler::framing_error(void) {} void console_handler::overrun(void) {} -void console_handler::rx_dma_transfer_complete(void) {} +void console_handler::rx_dma_transfer_complete(void) +{ + LL_DMA_DisableStream(m_rx_dma.get_dma(), m_rx_dma.get_stream()); + uint16_t rcvd_bytes = m_bytes_requested - m_reqd_bytes_registered - LL_DMA_GetDataLength(m_rx_dma.get_dma(), m_rx_dma.get_stream()); + if (rcvd_bytes) { + m_rx_buffer.produced(rcvd_bytes); + setup_receive(); + m_rx_buffer.commit(); + if (m_rx_callback) { + m_rx_callback->input_available(rcvd_bytes); + } + } +} void console_handler::rx_dma_half_transfer(void) {} @@ -53,6 +76,20 @@ void console_handler::tx_dma_transfer_complete(void) LL_DMA_DisableStream(m_tx_dma.get_dma(), m_tx_dma.get_stream()); } +void console_handler::transmission_complete(void) +{ + m_tx_buffer.consumed(m_bytes_sent); + if (m_tx_buffer.commited()) { + uint8_t const *chunk; + m_tx_buffer.get_chunk(chunk, m_bytes_sent); + if (m_bytes_sent) { + setup_transmit(chunk, m_bytes_sent); + } + } else { + m_bytes_sent = 0; + } +} + void console_handler::tx_dma_half_transfer(void) {} void console_handler::tx_dma_error(dma_helper::dma_error_type reason) @@ -60,7 +97,7 @@ void console_handler::tx_dma_error(dma_helper::dma_error_type reason) (void)reason; } -size_t console_handler::append(char const *s) +console_handler::size_type console_handler::append(char const *s) { size_t len = strlen(s); if (!len) { @@ -76,14 +113,14 @@ void console_handler::flush() } m_tx_buffer.commit(); - if (m_in_flight_size) { + if (m_bytes_sent) { return; } uint8_t const *chunk; - m_tx_buffer.get_chunk(m_tx_buffer.size(), chunk, m_in_flight_size); - if (m_in_flight_size) { - setup_transmit(chunk, m_in_flight_size); + m_tx_buffer.get_chunk(chunk, m_bytes_sent); + if (m_bytes_sent) { + setup_transmit(chunk, m_bytes_sent); } } diff --git a/components/f4ll/src/fault.cpp b/components/f4ll/src/fault.cpp index 83ae3c2..d89b280 100644 --- a/components/f4ll/src/fault.cpp +++ b/components/f4ll/src/fault.cpp @@ -6,7 +6,7 @@ * -c "tpiu config internal uart off " */ #include -// #include + #include #include #include diff --git a/components/f4ll/src/ringbuffer.cpp b/components/f4ll/src/ringbuffer.cpp new file mode 100644 index 0000000..ae81ac2 --- /dev/null +++ b/components/f4ll/src/ringbuffer.cpp @@ -0,0 +1,152 @@ +#include + +#include + +namespace f4ll { + +ringbuffer_ext::ringbuffer_ext(uint8_t *bptr, size_type bsize) + : m_buffer(bptr), + m_bsize(bsize) +{ +} + +iringbuffer::size_type ringbuffer_ext::put(uint8_t const *data, size_type len) +{ + size_type chunk1 = 0; + size_type chunk2 = 0; + + if (!data || !len) { + return 0; + } + + size_type max_len = unused(); + len = len < max_len ? len : max_len; + + chunk1 = m_bsize - m_head_shadow; + if (chunk1 >= len) { + chunk1 = len; + } else { + chunk2 = len - chunk1; + } + + std::memcpy(m_buffer + m_head_shadow, data, chunk1); + m_head_shadow += chunk1; + if (m_head_shadow == m_bsize) { + m_head_shadow = 0; + } + + if (chunk2) { + std::memcpy(m_buffer, data + chunk1, chunk2); + m_head_shadow += chunk2; + if (m_head_shadow == m_bsize) { + m_head_shadow = 0; + } + } + + return len; +} + +void ringbuffer_ext::commit() +{ + m_head = m_head_shadow; +} + +bool ringbuffer_ext::get_chunk(uint8_t const *&data, size_type &len) const +{ + size_type head = m_head; + size_type tail = m_tail; + size_type chunk_size = head >= tail ? head - tail : m_bsize - tail; + + if (!chunk_size) { + len = 0; + return tail != head; + } + + data = m_buffer + tail; + len = chunk_size; + + tail += chunk_size; + if (tail == m_bsize) { + tail = 0; + } + + return tail != head; +} + +void ringbuffer_ext::consumed(size_type len) +{ + if (!len) { + return; + } + m_tail += len; + if (m_tail == m_bsize) { + m_tail = 0; + } +} + +iringbuffer::size_type ringbuffer_ext::max_chunk_len() const +{ + if (m_tail <= m_head_shadow) { + return m_bsize - m_head_shadow - (m_tail ? 0 : 1); + } else { + return m_tail - m_head_shadow - 1; + } +} + +uint8_t *ringbuffer_ext::get_free_chunk(size_type &len) +{ + len = max_chunk_len(); + + return m_buffer + m_head_shadow; +} + +bool ringbuffer_ext::produced(size_type len) +{ + size_type max_len = max_chunk_len(); + if (len > max_len) { + return false; + } + m_head_shadow += len; + if (m_head_shadow == m_bsize) { + m_head_shadow = 0; + } + return true; +} + +iringbuffer::size_type ringbuffer_ext::uncommited() const +{ + return marker_diff(m_head_shadow, m_head); +} + +iringbuffer::size_type ringbuffer_ext::commited() const +{ + return marker_diff(m_head, m_tail); +} + +void ringbuffer_ext::discard() +{ + m_head_shadow = m_head; +} + +iringbuffer::size_type ringbuffer_ext::size() const +{ + return m_bsize; +} + +iringbuffer::size_type ringbuffer_ext::used() const +{ + return marker_diff(m_head_shadow, m_tail); +} + +iringbuffer::size_type ringbuffer_ext::unused() const +{ + return m_bsize - used() - 1; +} + +iringbuffer::size_type ringbuffer_ext::marker_diff(size_type m1, size_type m2) const +{ + return (m1 >= m2) ? (m1 - m2) : (m_bsize - m2 + m1); +} + +// +} diff --git a/components/f4ll/src/str_util.cpp b/components/f4ll/src/str_util.cpp index 54b95df..9b6ef95 100644 --- a/components/f4ll/src/str_util.cpp +++ b/components/f4ll/src/str_util.cpp @@ -1,7 +1,5 @@ #include -#include - ////////////////////////////////////////////////////////////////////////////// size_t strcpy_ex(char *dst, char const *src) {