/*!
 * \file
 *    thermostat_shield.c
 * \brief
 *    Nucleo thermostat shield port file. This file contain the implementation of driver
 *    calls for the shield.
 *
 * Author: Christos Choutouridis AEM: 8997
 * email : <cchoutou@ece.auth.gr>
 */
#include "thermostat_shield.h"


/*
 * =============== Digital I/O ===============
 */
static void SHIELD_LCD_Port_Init (void);
static void SHIELD_LED_Port_Init (void);
static void SHIELD_BRIDGE_Port_Init (void);
static void SHIELD_SR04_Port_Init (void);

/*
 * =============== LCD ===============
 * LCD_BD4  -- D8  -- PA9
 * LCD_BD5  -- D7  -- PA8
 * LCD_BD6  -- D6  -- PB10
 * LCD_BD7  -- D5  -- PB4
 * LCD_RS   -- D15 -- PB8
 * LCD_EN   -- D14 -- PB9
 * LCD_BL   -- D2  -- PA10
 */

/*!
 * LCD pin Initialize
 */
static void SHIELD_LCD_Port_Init (void) {
   GPIO_InitTypeDef  GPIO_InitType;

   __HAL_RCC_GPIOA_CLK_ENABLE ();
   __HAL_RCC_GPIOB_CLK_ENABLE ();

   GPIO_InitType.Mode  = GPIO_MODE_OUTPUT_PP;
   GPIO_InitType.Speed = GPIO_SPEED_LOW;
   GPIO_InitType.Pin   = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
   HAL_GPIO_Init(GPIOA, &GPIO_InitType);

   GPIO_InitType.Pin   = GPIO_PIN_4 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
   HAL_GPIO_Init(GPIOB, &GPIO_InitType);
}
void SHIELD_LCD_DB4 (uint8_t en) { _DOUTx(GPIOA, GPIO_PIN_9, en); }
void SHIELD_LCD_DB5 (uint8_t en) { _DOUTx(GPIOA, GPIO_PIN_8, en); }
void SHIELD_LCD_DB6 (uint8_t en) { _DOUTx(GPIOB, GPIO_PIN_10, en); }
void SHIELD_LCD_DB7 (uint8_t en) { _DOUTx(GPIOB, GPIO_PIN_4, en); }
void SHIELD_LCD_RS (uint8_t en)  { _DOUTx(GPIOB, GPIO_PIN_8, en); }
void SHIELD_LCD_EN (uint8_t en)  { _DOUTx(GPIOB, GPIO_PIN_9, en); }
void SHIELD_LCD_BL (uint8_t en)  { _DOUTx(GPIOA, GPIO_PIN_10, en); }

/*
 * =============== LED ===============
 * LED0 -- D4 -- PB5
 * LED1 -- D3 -- PB3
 */

/*!
 * LED pin initialize
 */
static void SHIELD_LED_Port_Init (void) {
   GPIO_InitTypeDef  GPIO_InitType;

   __HAL_RCC_GPIOB_CLK_ENABLE ();

   GPIO_InitType.Mode  = GPIO_MODE_OUTPUT_PP;
   GPIO_InitType.Speed = GPIO_SPEED_LOW;
   GPIO_InitType.Pin   = GPIO_PIN_3 | GPIO_PIN_5;
   HAL_GPIO_Init(GPIOB, &GPIO_InitType);
}
void SHIELD_LED0 (uint8_t on) { _DOUTx(GPIOB, GPIO_PIN_5, on); }
void SHIELD_LED1 (uint8_t on) { _DOUTx(GPIOB, GPIO_PIN_3, on); }

/*
 * =============== BRIDGE ===============
 * BR1 -- D10 -- PB6
 * BR2 -- D9  -- PC7
 */

/*!
 * H-Bridge pin initialize
 */
static void SHIELD_BRIDGE_Port_Init (void) {
   GPIO_InitTypeDef  GPIO_InitType;

   __HAL_RCC_GPIOB_CLK_ENABLE ();
   __HAL_RCC_GPIOC_CLK_ENABLE ();

   GPIO_InitType.Mode  = GPIO_MODE_OUTPUT_PP;
   GPIO_InitType.Speed = GPIO_SPEED_LOW;
   GPIO_InitType.Pin   = GPIO_PIN_6;
   HAL_GPIO_Init(GPIOB, &GPIO_InitType);
   GPIO_InitType.Pin   = GPIO_PIN_7;
   HAL_GPIO_Init(GPIOC, &GPIO_InitType);
}
void SHIELD_BR1 (uint8_t on)  { _DOUTx(GPIOB, GPIO_PIN_6, on); }
void SHIELD_BR2 (uint8_t on)  { _DOUTx(GPIOC, GPIO_PIN_7, on); }

/*
 *  =============== SR04 ===============
 *  TRIG -- D11 -- PA7
 *  ECHO -- D12 -- PA6
 */

/*!
 * SR04 pin initialize
 */
static void SHIELD_SR04_Port_Init (void) {
   GPIO_InitTypeDef  GPIO_InitType;

   __HAL_RCC_GPIOA_CLK_ENABLE ();

   GPIO_InitType.Mode  = GPIO_MODE_OUTPUT_PP;
   GPIO_InitType.Speed = GPIO_SPEED_LOW;
   GPIO_InitType.Pin   = GPIO_PIN_7;
   HAL_GPIO_Init(GPIOA, &GPIO_InitType);

   GPIO_InitType.Mode = GPIO_MODE_INPUT;
   GPIO_InitType.Pull = GPIO_NOPULL;
   GPIO_InitType.Pin  = GPIO_PIN_6;
   HAL_GPIO_Init(GPIOA, &GPIO_InitType);
}
void SHIELD_TRIG (uint8_t on) { _DOUTx(GPIOA, GPIO_PIN_7, on); }
uint8_t SHIELD_ECHO (void)    { return _DINx (GPIOA, GPIO_PIN_6); }

/*
 * ============= 1 Wire UART6 (AF08)===============
 *  1W_Tx   -- PA11 (OD+PU)
 *  1W_Rx   -- PA12 (I)
 */
static UART_HandleTypeDef h1w_uart;    //!< 1-wire uart handle

/*!
 * \brief
 *    This function handles UART Communication Timeout.
 * \param  huart:    Pointer to a UART_HandleTypeDef structure that contains
 *                   the configuration information for the specified UART module.
 * \param  Flag:     specifies the UART flag to check.
 * \param  Status:   The new Flag status (SET or RESET).
 * \param  Timeout:  Timeout duration
 * \return           HAL status
 */
static HAL_StatusTypeDef _WaitOnFlagUntilTimeout(UART_HandleTypeDef *huart, uint32_t Flag, FlagStatus Status, uint32_t Timeout) {
  uint32_t tickstart = HAL_GetTick();

  if (Status != RESET)  Status = SET;  /* Catch wrong Status */

  /* Wait until flag is on FlagStatus Status */
  while (__HAL_UART_GET_FLAG (huart, Flag) == Status) {
     if ((Timeout == 0) || ((HAL_GetTick() - tickstart ) > Timeout)) {
       /* Give up */
       huart->gState= HAL_UART_STATE_READY;  /* Mark Timeout as ready */
       __HAL_UNLOCK (huart);                 /* Process Unlocked */
       return HAL_TIMEOUT;                   /* Return the TIMEOUT */
     }
  }
  return HAL_OK;
}

/*!
 * \brief
 *    Initialize 1-Wire UART to 8bits, no parity, 1 stop, so it can
 *    be used for 1-Wire communication
 * \return  The status of the operation
 *    \arg  LLD_OK      Success
 *    \arg  LLD_ERROR   The Init failed.
 */
static LLD_Status_en _1W_UART_Init (void) {
   _1WIRE_UART_CLK_ENABLE (); // Enable 1-wire's USART clock

   /*
    * USART configured as follows:
    *  - Word Length = 8 Bits
    *  - Stop Bit    = One Stop bit
    *  - Parity      = No parity
    *  - BaudRate    = _1WIRE_UART_INIT_BR baud
    *  - Hardware flow control disabled (RTS and CTS signals)
    */
   h1w_uart.Instance        = _1WIRE_UART_INSTANCE;
   h1w_uart.Init.BaudRate   = _1WIRE_UART_INIT_BR;
   h1w_uart.Init.WordLength = UART_WORDLENGTH_8B;
   h1w_uart.Init.StopBits   = UART_STOPBITS_1;
   h1w_uart.Init.Parity     = UART_PARITY_NONE;
   h1w_uart.Init.Mode       = UART_MODE_TX_RX;

   if (HAL_UART_Init(&h1w_uart) != HAL_OK)
      return LLD_ERROR;
   return LLD_OK;
}


/*!
 * Init the 1wire interface and allocate all resources for it
 * \return  The status of the operation
 *    \arg  LLD_OK      Success
 *    \arg  LLD_ERROR   The Init failed.
 */
LLD_Status_en SHIELD_1W_Init (void) {
   GPIO_InitTypeDef GPIO_InitStruct;

   __HAL_RCC_GPIOA_CLK_ENABLE ();

   GPIO_InitStruct.Pin = GPIO_PIN_11;
   GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
   GPIO_InitStruct.Pull = GPIO_PULLUP;
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
   GPIO_InitStruct.Alternate = GPIO_AF8_USART6;
   HAL_GPIO_WritePin (GPIOA, GPIO_InitStruct.Pin, GPIO_PIN_SET);
   HAL_GPIO_Init (GPIOA, &GPIO_InitStruct);

   GPIO_InitStruct.Pin = GPIO_PIN_12;
   //GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   GPIO_InitStruct.Alternate = GPIO_AF8_USART6;
   GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
   /*^
    * Mark as alternate because HAL_GPIO_Init ()
    * can not configure Input + alternate
    */
   HAL_GPIO_Init (GPIOA, &GPIO_InitStruct);

   return _1W_UART_Init ();
}

/*!
 * \brief
 *    Set a Baudrate to the UART, to use for 1-Wire communication
 * \param   br    The desired baudrate
 * \return  The status of the operation (part of toolbox)
 *    \arg  DRV_ERROR   Fail
 *    \arg  DRV_READY   Success
 */
drv_status_en SHIELD_1W_UART_BR (uint32_t br) {
   /*
    * Keep USART configured as already set by Init:
    *  - Word Length = 8 Bits
    *  - Stop Bit    = One Stop bit
    *  - Parity      = No parity
    *  - Hardware flow control disabled (RTS and CTS signals)
    */
   if (! IS_UART_BAUDRATE (br) )
      return DRV_ERROR;
   h1w_uart.Init.BaudRate = br;

   /* Check the Over Sampling */
   if(h1w_uart.Init.OverSampling == UART_OVERSAMPLING_8) {
      /*------- UART-associated USART registers setting : BRR Configuration ------*/
      if((h1w_uart.Instance == USART1)){
         h1w_uart.Instance->BRR = UART_BRR_SAMPLING8 (HAL_RCC_GetPCLK2Freq(), h1w_uart.Init.BaudRate);
      }
      else {
         h1w_uart.Instance->BRR = UART_BRR_SAMPLING8 (HAL_RCC_GetPCLK1Freq(), h1w_uart.Init.BaudRate);
      }
   }
   else {
      /*------- UART-associated USART registers setting : BRR Configuration ------*/
      if((h1w_uart.Instance == USART1)) {
         h1w_uart.Instance->BRR = UART_BRR_SAMPLING16 (HAL_RCC_GetPCLK2Freq(), h1w_uart.Init.BaudRate);
      }
      else {
         h1w_uart.Instance->BRR = UART_BRR_SAMPLING16 (HAL_RCC_GetPCLK1Freq(), h1w_uart.Init.BaudRate);
      }
   }
   return DRV_READY;
}

/*!
 * \brief
 *    Read-Write functionality. We use the following USART configuration.
 *       - Word Length = 8 Bits
 *       - Stop Bit    = One Stop bit
 *       - Parity      = No parity
 * \return  The byte received. On failure return 0xFFFF (bus released state)
 * \note
 *    Due to the nature of the PCB, the received byte is the actual bus
 *    condition during the communication frame (time slot)
 */
uint16_t SHIELD_1W_RW (uint8_t byte)
{
   if (h1w_uart.Init.WordLength != UART_WORDLENGTH_8B)   return (uint8_t)0xFFFF;
   if (h1w_uart.Init.Parity != UART_PARITY_NONE)         return (uint8_t)0xFFFF;

   if (_WaitOnFlagUntilTimeout (&h1w_uart, UART_FLAG_TXE, RESET, _1WIRE_UART_TIMEOUT) != HAL_OK)
     return 0x1FF;
   WRITE_REG (h1w_uart.Instance->DR, (byte & (uint8_t)0xFF));
   if (_WaitOnFlagUntilTimeout (&h1w_uart, UART_FLAG_TC, RESET, _1WIRE_UART_TIMEOUT) != HAL_OK)
      return 0x2FF;
   //if (_WaitOnFlagUntilTimeout (&h1w_uart, UART_FLAG_RXNE, RESET, _1WIRE_UART_TIMEOUT) != HAL_OK)
   //     return 0xFFFF;
   return (uint8_t)(h1w_uart.Instance->DR & (uint8_t)0x00FF);
}

/*!
 * \brief
 *    Receive functionality. We use USART blocking mode.
 * \return  The byte received. On failure return 0xFF (bus released state)
 * \note
 *    Due to the nature of the PCB, the received byte is the actual bus
 *    condition during the communication frame (time slot)
 */
uint8_t SHIELD_1W_Rx (void) {
   uint8_t rx;
   if (HAL_UART_Receive (&h1w_uart, &rx, sizeof (uint8_t), _1WIRE_UART_TIMEOUT) != HAL_OK)
      rx = 0xFF;
   return rx;
}

/*!
 * \brief
 *    Transmit functionality. We use USART blocking mode.
 * \return  The status of transition
 *    \arg  0  Success
 *    \arg  1  Fail
 */
uint8_t SHIELD_1W_Tx (uint8_t byte) {
   if (HAL_UART_Transmit (&h1w_uart, &byte, sizeof (uint8_t), _1WIRE_UART_TIMEOUT) != HAL_OK)
      return 1;
   return 0;
}

/*!
 * Shield hardware initialization
 */
LLD_Status_en SHIELD_Init (void) {
   SHIELD_LCD_Port_Init ();
   SHIELD_LED_Port_Init ();
   SHIELD_BRIDGE_Port_Init ();
   SHIELD_SR04_Port_Init ();

   SHIELD_1W_Init ();
   COM_Init ();
   return LLD_OK;
}

/*
 * ============= Serial console UART2 (AF07)===============
 *  COM_Tx -- PA2 (PP)
 *  COM_Rx -- PA3 (I)
 */
static UART_HandleTypeDef com_huart;   //!< com uart handle
static deque08_t  _com_rxq;            //!< deque object
static byte_t     _com_rxbuffer[COM_BUFFER_SIZE];  //!< buffer for deque

/*!
 * \brief
 *    Called from USART IRQ to put the read character to queue
 * \param      Pointer to a UART_HandleTypeDef structure that contains
 *             the configuration information for the specified UART module.
 *
 * \return     The status of the operation
 *    \arg     HAL_ERROR      Fail
 *    \arg     HAL_OK         Success
 */
static HAL_StatusTypeDef _UART_read_data (UART_HandleTypeDef *huart, deque08_t *q) {
   uint8_t  r;

   __HAL_LOCK(huart);   /*
                         * We don't try to receive valid data while the USART is
                         * locked from transmitter. It's OK ;)
                         */

   /* Receive data based on Word length and parity */
   switch (huart->Init.WordLength) {
      default:
      case UART_WORDLENGTH_8B:
         if(huart->Init.Parity == UART_PARITY_NONE)
            r = (uint8_t)(huart->Instance->DR & (uint16_t)0x00FF);
         else
            r = (uint8_t)(huart->Instance->DR & (uint16_t)0x007F);
         break;
      case UART_WORDLENGTH_9B:
         if(huart->Init.Parity == UART_PARITY_NONE) {
            r = (uint8_t)(huart->Instance->DR & (uint16_t)0x01FF);
            __HAL_UNLOCK(huart);
            return HAL_ERROR;
            /* Not supported Configuration */
         } else
            r = (uint8_t)(huart->Instance->DR & (uint16_t)0x00FF);
         break;
   }
   deque08_push_back (q, r);
   /*!<
    * \note
    *    We queue the received bytes. The user application MUST
    *    read the queue in a regular basis, or else this IRQ will
    *    find queue full and we will have data loss.
    */

   __HAL_UNLOCK(huart);
   return HAL_OK;
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
   __HAL_UART_CLEAR_PEFLAG (huart);
   huart->ErrorCode = HAL_UART_ERROR_NONE;
   huart->gState = HAL_UART_STATE_READY;
   /*
    * Clear all the error flag at once,
    * Set USART READY for re-start,
    * Error Callback
    */
}
/*!
 * \brief
 *    USART serial handler. Pushes every received character to a queue.
 *
 * In the IRQ handler there is only Rx functionality provided by this driver.
 * The Error handling call the HAL's callback (which are empty)
 * The Tx part, is not implemented
 */
void USART2_IRQHandler (void) {
   uint32_t tmp_flag = 0, tmp_it_source = 0;

   // ======= Error handler =========
   if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_PE)) != RESET) &&
      ((tmp_it_source = __HAL_UART_GET_IT_SOURCE(&com_huart, UART_IT_PE)) != RESET)) {
      /* UART parity error interrupt occurred */
      com_huart.ErrorCode |= HAL_UART_ERROR_PE;
   }
   if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_FE)) != RESET) &&
      ((tmp_it_source = __HAL_UART_GET_IT_SOURCE(&com_huart, UART_IT_ERR)) != RESET)) {
      /* UART frame error interrupt occurred */
      com_huart.ErrorCode |= HAL_UART_ERROR_FE;
   }
   if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_NE)) != RESET) &&
       (tmp_it_source != RESET)){
      /* UART noise error interrupt occurred */
      com_huart.ErrorCode |= HAL_UART_ERROR_NE;
   }
   if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_ORE)) != RESET) &&
       (tmp_it_source != RESET)){
      /* USART Over-Run interrupt occurred */
      com_huart.ErrorCode |= HAL_UART_ERROR_ORE;
   }

   if(com_huart.ErrorCode != HAL_UART_ERROR_NONE) {
      HAL_UART_ErrorCallback (&com_huart);
   }

   // ====== Get Data =========
   if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_RXNE)) != RESET) &&
      ((tmp_it_source = __HAL_UART_GET_IT_SOURCE(&com_huart, UART_IT_RXNE)) != RESET)) {
      // Read byte
      _UART_read_data (&com_huart, &_com_rxq);  // Don't check return status
   }

}

/*!
 * \brief
 *    Initialize the UART and UART IRQ handler
 * \return  The status of the operation
 *    \arg  LLD_ERROR      Fail
 *    \arg  LLD_OK         Success
 */
static LLD_Status_en _COM_UART_Init (void) {
   /*
    * Enable UART clock
    */
   _COM_CLK_ENABLE();

   deque08_link_buffer (&_com_rxq, _com_rxbuffer);
   deque08_set_capacity (&_com_rxq, COM_BUFFER_SIZE);
   deque08_init (&_com_rxq);

   /*
    * USART configured as follows:
    *  - Word Length = 8 Bits
    *  - Stop Bit    = One Stop bit
    *  - Parity      = No parity
    *  - BaudRate    = COM_BAUDRATE baud
    *  - Hardware flow control disabled (RTS and CTS signals)
    */
   com_huart.Instance        = COM_UART_INSTANCE;
   com_huart.Init.BaudRate   = COM_UART_BAUDRATE;
   com_huart.Init.WordLength = UART_WORDLENGTH_8B;
   com_huart.Init.StopBits   = UART_STOPBITS_1;
   com_huart.Init.Parity     = UART_PARITY_NONE;
   com_huart.Init.Mode       = UART_MODE_TX_RX;

   if (HAL_UART_Init(&com_huart) != HAL_OK)
      return LLD_ERROR;

   /*
    * Enable IRQ for Rx
    * Tx IRQ enabled by COM_transmit ()
    */
   HAL_NVIC_SetPriority (COM_UART_IRQ, 0x0D, 0);
   HAL_NVIC_EnableIRQ (COM_UART_IRQ);

   /* Enable the UART Data Register not empty Interrupt */
   __HAL_UART_ENABLE_IT(&com_huart, UART_IT_RXNE);
   /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
   //__HAL_UART_ENABLE_IT(&com_huart, UART_IT_ERR);

   return LLD_OK;
}


/*!
 * Initialize the COM dedicated I/O and allocate resources
 * \return The status of the operation
 */
LLD_Status_en COM_Init (void) {
   GPIO_InitTypeDef GPIO_InitStruct;

   __HAL_RCC_GPIOA_CLK_ENABLE ();

   GPIO_InitStruct.Pin = GPIO_PIN_2;
   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
   GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
   HAL_GPIO_Init (GPIOA, &GPIO_InitStruct);

   GPIO_InitStruct.Pin = GPIO_PIN_3;
   GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
//   GPIO_InitStruct.Pull = GPIO_NOPULL;
//   GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
   HAL_GPIO_Init (GPIOA, &GPIO_InitStruct);

   return _COM_UART_Init();
}

/*!
 * \brief
 *    Set UART baudrate
 * \param   br The desired baudrate
 * \return  The status of the operation
 *    \arg  LLD_ERROR      Fail
 *    \arg  LLD_OK         Success
 */
LLD_Status_en COM_baudrate (uint32_t br) {
   // Change only the Baudrate
   com_huart.Init.BaudRate   = br;
   if (HAL_UART_Init(&com_huart) != HAL_OK)
      return LLD_ERROR;
   return LLD_OK;
}

/*!
 * \brief
 *    USART's putchar functionality to link with io system
 * This function is compatible with putchar() in "stdio.h"
 */
int COM_putchar (char c) {
   if (_WaitOnFlagUntilTimeout (&com_huart, UART_FLAG_TC, RESET, COM_UART_PUTCHAR_TIMEOUT) != HAL_OK)
     return 0xFFFF;
   WRITE_REG (COM_UART_INSTANCE->DR, (c & (uint8_t)0xFF));
   /*!<
    * \note
    *    The sequence:
    *    - Read operation to USART_SR register  [USART_GetFlagStatus()]
    *    - Write operation to USART_DR register [USART_SendData()]
    *    clears the TC Flag
    *
    *    The TXE Flag is cleared by the write operation to USART_DR register
    *    [USART_SendData()]
    */
   return (int)c;
}

/*!
 * \brief
 *    USART's getchar functionality to link with io system
 * This function is compatible with getchar() in "stdio.h"
 */
int COM_getchar (void) {
   clock_t mark = clock ();
   clock_t to   = COM_UART_GETCHAR_TIMEOUT*get_freq();
   clock_t now;
   byte_t  r=0;

   while (deque08_pop_front (&_com_rxq, &r) == 0) {
      now = clock ();
      if (_CLOCK_DIFF(now, mark) >= to)
         return 0;
   }
   return r;
}

/*!
 * \brief
 *    Transmit functionality to link with io system
 * This function is compatible with htp tx functionality
 *
 * \param   data  Pointer to data buffer
 * \param   size  Size of buffer (number of bytes)
 * \return  The number of bytes to transmit
 */
int COM_Transmit (uint8_t *data, int size) {
   int r = size;

   while (size--) {
      //queue08_push (&_com_txq, (byte_t)*data);
      COM_putchar(*data++);
   }
   _WaitOnFlagUntilTimeout (&com_huart, UART_FLAG_TC, SET, COM_UART_PUTCHAR_TIMEOUT);
   return r;
}

/*!
 * \brief
 *    Check receive functionality synchronized to IRQ
 * This function is compatible with htp rx functionality
 *
 * \return  The number of bytes on queue (<package_size> indicates done)
 */
int COM_CheckReceive (void) {
   return deque08_size (&_com_rxq);
}

/*!
 * \brief
 *    Receive flush functionality to link with io system
 * This function is compatible with htp rx functionality
 *
 * \param   data  Pointer to data buffer
 * \param   size  Size of buffer (number of bytes)
 * \return  The number of received bytes
 */
void COM_ReceiveFlush (void) {
   deque08_flush (&_com_rxq);
}

/*!
 * \brief
 *    Receive functionality to link with io system
 * This function is compatible with htp rx functionality
 *
 * \param   data  Pointer to data buffer
 * \param   size  Size of buffer (number of bytes)
 * \return  The number of received bytes
 */
int COM_Receive (uint8_t *data, int size) {
   int i;
   uint8_t r=1, b;

   for (i=0 ; r !=0 && i<size ; ++i) {
      r = deque08_pop_front (&_com_rxq, &b);
      data[i] = b;
   }
   return i;
}
