#ifndef MDR32F9Q_UART_H
#define MDR32F9Q_UART_H

/*
 * uart_device.hpp
 * ru utf8
 *
 *  Created on: 28 нояб. 2018 г.
 *      Author: alexrayne <alexraynepe196@gmail.com>
  ------------------------------------------------------------------------
    Copyright (c) alexrayne

   All rights reserved.
   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:
   - Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
   - Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in the
     documentation and/or other materials provided with the distribution.
   - Neither the name of ARM nor the names of its contributors may be used
     to endorse or promote products derived from this software without
     specific prior written permission.
   *
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE. *
 *-----------------------------------------------------------------
 * реализация драйвера УАРТ с буффером на ВЕ94Т. ВЕ94Т несет разновидность УАРТ
 * стиля 16C650 с некоторыми нюансами.
 * драйвер использует режим ФИФО, и ведет обработку приема/передачи на прерывании.
 *      ФИФО сигналит при заполнении половины приемника, или когда останется 2
 *          символа в передатчике
 * всегда активно прерывание приема, и таймаут на 32бит по приему.
 * на скорости 115200 таймаут дает 0.25мс задержку приема пакета/фрейма.
 *
 * для обозначения предлагаемого драйвера УАРТ для проекта заявлен
 *      тип UARTDevice - псевдоним UART_BUF_16C650
 *
 * Пример использвания:
 * Usage:
 *      UART_BUF_16C650 uartx;
 *      void uartx_init(){
 *          // настрою uartx на УАРТ1 на портеА, с настройкой USART_1152008N1
 *          uartx.init(USART1ABuf_init);
 *      }
 *      extern "C"  void UART1_IRQHandler(void)
 *      {
 *          uartx.IRQ();
 *      }
 *
 *  TODO: реализовать режим DMA - критично для приемника, позволит без сбоев
 *      принимать пакеты при длительном активировании прерывания модели.
 *      \sa model_unit
*/


#include <mcu_usart.h>
#include <mcu_rcc.h>
#include <mcu_gpio.h>
#include <mcu_nvic.h>
//#include <mcu_dma.h>

#include "hal_device.h"
#include "lib/hal_ringbuffer.h"
#include "uart_hal.h"

#include <OsSync.h>



// структура описания железа УАРТА
struct UART_DEV_INIT{

  // УАРТ
  USART_TypeDef* USARTx;
  // начальные настройки
  const USART_InitTypeDef * USART_InitStructure;
  // насройка контроллера прерыаний от УАРТ
  const NVIC_InitTypeDef *  NVIC_InitStructure;

  // настройка доменов тактовой частоты
  uint32_t RCC_Perifery;

  // настройки пинов, на которые подключить уарт
  const GPIOFUNC_INIT*  GPIOPINS;
};



class UART_BUF_16C650
    : public UART_BUFDevice
    //, public HAL_Device
{
public:
    typedef UART_BUFDevice  inherited;
    typedef UART_DEV_INIT   DEV_INIT;


    UART_BUF_16C650();
    UART_BUF_16C650(const DEV_INIT& usart_init);

    // инициализация порта, и вего его железа, и включение прерываний
    void init(const DEV_INIT& usart_init);
    void deinit(void);

    // переключение УАРТ на соответствующие пины
    void connect_gpio(const DEV_INIT& usart_init ); //const GPIOFUNC_INIT*  GPIOPINS


public:
    // обработчик прерываний УАРТа.
    void IRQ();
    void IRQtx();
    void IRQrx();

    // there HW specific TX completion API
    //  check tx is active
    virtual bool tx_busy() {
        return  (USARTx->FR & UART_FLAG_BUSY) != 0;
    };
    //  invokes wait until tx is done and inactive
    virtual WaitResult tx_wait();

    //virtual int setPower(POWER_STATE state);

protected:
    typedef USART_TypeDef   USART_io;
    USART_io*  USARTx;
    const DEV_INIT* init_state;
    //* позволяет форсировать сигнал rx_avail при непустом буфере
    //*   с этим периодом
    static const unsigned rx_sig_force_to = 4;
    using inherited::init;

    virtual int SendData(const void *data, const u32 data_size);
    virtual int send_char(int x);
    // делает основную работу по отправке tx в порт УАРТа
    // \return true - IRQ enabled
    bool    tx_send_full();

};


// этот тип позиционирую как дефолтовый драйвер УАРТ в проекте
typedef UART_BUF_16C650 UARTDevice;




/*
class UART_DMADevice
    : public UART_BUF_16C650
{
public:
    typedef UART_BUF_16C650 inherited;

    typedef DMA_Stream_TypeDef* dma_stream_p;
    struct DMA_INIT{
        //DMA_TypeDef*        dma;
        dma_stream_p        stream;
        uint32_t            rcc;
        uint32_t            ch;
        uint32_t            tcif;
        u8                  IRQn;
        u8                  prio;
    };


    struct DEVDMA_INIT : public inherited::DEV_INIT {
      const DMA_INIT*       rx_dma;
      const DMA_INIT*       tx_dma;
    };

    UART_DMADevice();
    UART_DMADevice(const DEVDMA_INIT& usart_init);
    UART_DMADevice(const DEV_INIT& usart_init);
    virtual ~UART_DMADevice();

    void init(const DEVDMA_INIT& usart_init);
    void deinit(void);

    void IRQ();
    void IRQtx();
    void IRQrx();

    virtual i32 setPower(POWER_STATE state);
    virtual bool rx_wait(unsigned to = toInfinite);
public:
    // init rx DMA
    void init_rx(const DMA_INIT& hdma);
    void init_tx(const DMA_INIT& hdma);
protected:
    dma_stream_p    dma_rx;
    dma_stream_p    dma_tx;
    unsigned    dma_tx_len;
    unsigned    dma_tx_tcif;
    unsigned    dma_tx_limit(unsigned len) const {
        if (len < 32)
            return len;
        else
            return 32;
    };
    //void        dma_start();
    void        dma_stop();
    void        dmarx_stop();

    // сверяет еткущий статус
    // \return true when rx buffer changes
    bool        dmarx_poll();
    //  вызов dmarx_poll вне контекста прерывания
    bool        dmarx_online_poll();

    void        dmatx_start(uint32_t src, unsigned size);
    void        dmatx_stop();
    bool        dmatx_poll();

protected:
    const DEV_INIT* init_state(){
        return (const DEV_INIT*) inherited::init_state;
    };
    void init(void);
};

#define UART1RX_DMA_IRQHandler      DMA2_Stream5_IRQHandler
#define UART1TX_DMA_IRQHandler      DMA2_Stream7_IRQHandler
#define UART2TX_DMA_IRQHandler      DMA1_Stream6_IRQHandler
*/


//-----------------------------------------------------------------------------
// типовые настройки УАРТов на 1152008N1, для разных портов 1886ВЕ94Т

// uasrt settings 115200 No parity 1stop
extern const USART_InitTypeDef      USART_1152008N1;
extern const UART_BUF_16C650::DEV_INIT  USART1ABuf_init;
extern const UART_BUF_16C650::DEV_INIT  USART1BBuf_init;
extern const UART_BUF_16C650::DEV_INIT  USART1DBuf_init;
extern const UART_BUF_16C650::DEV_INIT  USART1EBuf_init;
extern const UART_BUF_16C650::DEV_INIT  USART2FBuf_init;

#endif // V12_UART_H
