diff --git a/inc/f4ll/console_handler.h b/inc/f4ll/console_handler.h index 27a2a7e..4e21029 100644 --- a/inc/f4ll/console_handler.h +++ b/inc/f4ll/console_handler.h @@ -18,12 +18,21 @@ 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); 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); // LL_UsartCore pure virtual function implementations virtual void receiver_idle(void) override; @@ -37,8 +46,12 @@ 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; + iconsole_input *m_rx_callback; }; } /* namespace f4ll */ diff --git a/inc/f4ll/ringbuffer.h b/inc/f4ll/ringbuffer.h index 9ba2ccc..82f1891 100644 --- a/inc/f4ll/ringbuffer.h +++ b/inc/f4ll/ringbuffer.h @@ -35,22 +35,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; @@ -80,8 +88,13 @@ public: 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; @@ -98,6 +111,7 @@ private: size_type m_tail = 0; //!< Read position size_type marker_diff(size_type m1, size_type m2) const; + size_type max_chunk_len() const; }; // diff --git a/inc/f4ll/usart_core.h b/inc/f4ll/usart_core.h index 508df34..fa17f2d 100644 --- a/inc/f4ll/usart_core.h +++ b/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/src/console_handler.cpp b/src/console_handler.cpp index a4ba4a6..eb8cd10 100644 --- a/src/console_handler.cpp +++ b/src/console_handler.cpp @@ -5,6 +5,7 @@ * Author: abody */ +#include #include #include #include @@ -13,24 +14,39 @@ 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) { } -void console_handler::receiver_idle(void) {} +void console_handler::receiver_idle(void) +{ + if (!m_rx_callback) { + return; + } + uint16_t rcvd_bytes = m_bytes_requested - LL_DMA_GetDataLength(m_rx_dma.get_dma(), m_rx_dma.get_stream()); + size_type len; + uint8_t const *data; + bool more_data = m_rx_buffer.get_chunk(data, len); + m_rx_callback->input_available(len); +} void console_handler::transmission_complete(void) { - m_tx_buffer.consumed(m_in_flight_size); + m_tx_buffer.consumed(m_bytes_sent); 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); + m_tx_buffer.get_chunk(chunk, m_bytes_sent); + if (m_bytes_sent) { + setup_transmit(chunk, m_bytes_sent); } } else { - m_in_flight_size = 0; + m_bytes_sent = 0; } } @@ -76,14 +92,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/src/ringbuffer.cpp b/src/ringbuffer.cpp index 5354f95..462c4d1 100644 --- a/src/ringbuffer.cpp +++ b/src/ringbuffer.cpp @@ -49,12 +49,8 @@ void ringbuffer_ext::commit() m_head = m_head_shadow; } -bool ringbuffer_ext::get_chunk(size_type len_requested, uint8_t const *&data, size_type &len) const +bool ringbuffer_ext::get_chunk(uint8_t const *&data, size_type &len) const { - if (!len_requested) { - return false; - } - size_type head = m_head; size_type tail = m_tail; size_type chunk_size = head >= tail ? head - tail : m_bsize - tail; @@ -64,9 +60,6 @@ bool ringbuffer_ext::get_chunk(size_type len_requested, uint8_t const *&data, si return tail != head; } - if (chunk_size > len_requested) { - chunk_size = len_requested; - } data = m_buffer + tail; len = chunk_size; @@ -89,6 +82,35 @@ void ringbuffer_ext::consumed(size_type len) } } +iringbuffer::size_type ringbuffer_ext::max_chunk_len() const +{ + if (m_tail <= m_head_shadow) { + return m_bsize - m_head_shadow; + } 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);