/*
 *   Copyright (c) 2020 by Jonathan Naylor G4KLX
 *   Copyright (c) 2020 by Geoffrey Merck F4FXL - KC3FRA   
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#if defined(STM32F4XX) || defined(STM32F7XX)

#include "STMUART.h"

CSTMUART::CSTMUART() :
m_usart(NULL)
{

}

void CSTMUART::init(USART_TypeDef* usart)
{
  m_usart = usart;
}

void CSTMUART::write(const uint8_t * data, uint16_t length)
{
  if (length == 0U || m_usart == NULL)
    return;

  m_txFifo.put(data[0]);
  USART_ITConfig(m_usart, USART_IT_TXE, ENABLE);	// Switch TX IRQ is on

  for (uint16_t i = 1U; i < length; i++)
    m_txFifo.put(data[i]);

  USART_ITConfig(m_usart, USART_IT_TXE, ENABLE);	// Make sure TX IRQ is on
}

uint8_t CSTMUART::read()
{
  return m_rxFifo.get();
}

void CSTMUART::handleIRQ()
{
  if (m_usart == NULL)
    return;

  if (USART_GetITStatus(m_usart, USART_IT_RXNE)) {
    if (!m_rxFifo.isFull())
      m_rxFifo.put((uint8_t) USART_ReceiveData(m_usart));

    USART_ClearITPendingBit(USART1, USART_IT_RXNE);
  }

  if (USART_GetITStatus(m_usart, USART_IT_TXE)) {
    if (!m_txFifo.isEmpty())
      USART_SendData(m_usart, m_txFifo.get());

    USART_ClearITPendingBit(m_usart, USART_IT_TXE);

    if (m_txFifo.isEmpty())	// If there's no more data to transmit then turn off TX interrupts
      USART_ITConfig(m_usart, USART_IT_TXE, DISABLE);
  }
}

// Flushes the transmit shift register
// warning: this call is blocking
void CSTMUART::flush()
{
  if (m_usart == NULL)
    return;

  // wait until the TXE shows the shift register is empty
  while (USART_GetITStatus(m_usart, USART_FLAG_TXE))
    ;
}

uint16_t CSTMUART::available()
{
  return m_rxFifo.isEmpty() ? 0U : 1U;
}

uint16_t CSTMUART::availableForWrite()
{
  return m_txFifo.isFull() ? 0U : 1U;
}

#endif
