/**
 * @file CBSP_AsyncComm.h
 * @author owalter
 * @brief
 * @version 0.1

 * @date 28.11.2022
 *
 * @copyright Copyright © 2022 habemus! electronic + transfer GmbH.  All rights reserved.
 */
#ifndef NUN10K22_DISPLAY_CBSP_ASYNCCOMM_H
#define NUN10K22_DISPLAY_CBSP_ASYNCCOMM_H

#include <stdint.h>

#include "cmsis_os.h"
#include "lwrb.h"
#include "main.h"

typedef void (*data_receive_callback)(const void* data, size_t len);
typedef void (*char_receive_callback)(const char* str, size_t len);
typedef void (*bytes_receive_callback)(const uint8_t* str, size_t len);

/**
 * \brief           Volatile data structure
 *
 * Variables declared using this structure can not be put to non-volatile memory (such as flash, EEPROM, ..)
 */
typedef struct {
    /* OS queue */
    osMessageQueueId_t queue; /*!< Message queue */

    /* Raw data buffer */
    uint8_t dma_rx_buffer[1024]; /*!< DMA buffer for receive data */
    size_t  old_pos;             /*!< Position for data */

    /* Tx data buffer */
    volatile size_t tx_dma_current_len;
    volatile uint8_t tx_running;
    lwrb_t          tx_rb;
    uint8_t         tx_rb_data[512];
} uart_desc_volatile_t;

/**
 * \brief           Non-Volatile data structure
 *
 * Variables declared using this structure may be put to non-volative memory.
 * This is to avoid using RAM for constant data
 */
typedef struct {
    /* UART config */
    USART_TypeDef* uart; /*!< UART/USART/LPUART instance */
#ifndef USE_HAL_DRIVER
    GPIO_TypeDef* uart_tx_port;
    GPIO_TypeDef* uart_rx_port;
    uint16_t      uart_tx_pin;
    uint16_t      uart_rx_pin;
    uint16_t      uart_tx_pin_af;
    uint16_t      uart_rx_pin_af;

    /* Interrupts config */
    uint8_t   prio;       /*!< Preemption priority number */
    IRQn_Type uart_irq;   /*!< UART IRQ instance */
    IRQn_Type dma_irq_rx; /*!< DMA IRQ RX instance */
    IRQn_Type dma_irq_tx; /*!< DMA IRQ TX instance */

    /* DMA config & flags management */
    uint32_t dma_rx_req; /*!< RX DMA request */
    uint32_t dma_tx_req; /*!< TX DMA request */

#endif

    DMA_TypeDef* dma_rx;    /*!< RX DMA instance */
    uint32_t     dma_rx_ch; /*!< RX DMA channel */
    void (*dma_rx_clear_tc_fn)(DMA_TypeDef*);
    void (*dma_rx_clear_ht_fn)(DMA_TypeDef*);
    uint32_t (*dma_rx_is_tc_fn)(DMA_TypeDef*);
    uint32_t (*dma_rx_is_ht_fn)(DMA_TypeDef*);

    DMA_TypeDef* dma_tx;    /*!< TX DMA instance */
    uint32_t     dma_tx_ch; /*!< TX DMA channel */
    void (*dma_tx_clear_tc_fn)(DMA_TypeDef*);
    uint32_t (*dma_tx_is_tc_fn)(DMA_TypeDef*);
    void (*dma_tx_clear_ht_fn)(DMA_TypeDef*);
    void (*dma_tx_clear_gi_fn)(DMA_TypeDef*);
    void (*dma_tx_clear_te_fn)(DMA_TypeDef*);
    void (*dma_tx_clear_fe_fn)(DMA_TypeDef*);

    uart_desc_volatile_t* data; /*!< Pointer to volatile data */

    /* receive callback */
    data_receive_callback uart_external_receive_callback;

} uart_desc_t;

/* USART related functions */
osThreadId_t usart_init(const uart_desc_t* uart, const osThreadAttr_t* attr);
void         usart_dma_irq_handler(const uart_desc_t* uart);
void         usart_dma_irq_handler_tx(const uart_desc_t* uart);
void         usart_irq_handler(const uart_desc_t* uart);
void         usart_send_data(const uart_desc_t* uart, const void* data, size_t len);

/**
 * \brief           Calculate length of statically allocated array
 */
#define ARRAY_LEN(x) (sizeof(x) / sizeof((x)[0]))

#endif  // NUN10K22_DISPLAY_CBSP_ASYNCCOMM_H
