/*
 * $LastChangedRevision: 3952 $
 * $LastChangedDate:: 2025-11-27 21:04:55 +0100#$
 *
 * This file is part of X2C. web: x2c.lcm.at
 *
 * Copyright (c) 2023, Linz Center of Mechatronics GmbH (LCM), web: x2c.lcm.at
 * All rights reserved.
 */
/*
 * This file is licensed according to the BSD 3-clause license as follows:
 *
 * 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 the "Linz Center of Mechatronics GmbH" and "LCM" 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 "Linz Center of Mechatronics GmbH" 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.
 */
#include "Target.h"
#include "Main.h"
#include "Hardware.h"

/* Private macros */
#define X2C_UART_TIMEOUT  ((uint32)32767)

/* CPU temperature related macros */
#define TEMP30_CAL_ADDR   ((uint16*) ((uint32) 0x1FFF75A8)) /* Address of temperature sensor voltage measured at 30 degree Celsius */
#define TEMP130_CAL_ADDR  ((uint16*) ((uint32) 0x1FFF75CA)) /* Address of temperature sensor voltage measured at 130 degree Celsius */
#define VDD_CALIB         ((uint16) (300))                  /* Vdd voltage during calibration (voltage at factory) */
#define VDD_APPLI         ((uint16) (330))                  /* Vdd voltage of application (voltage on Nucleo board) */


/* Private prototypes */
static void sendSerial(tSerial* serial, uint8 data);
static uint8 receiveSerial(tSerial* serial);
static uint8 isReceiveDataAvailable(tSerial* serial);
static uint8 isSendReady(tSerial* serial);

/* Global variables */
extern UART_HandleTypeDef huart2;


/**
 * This function initializes the X2C driver and adds the X2C driver hook functions for the protocol interface.
 * The USART peripheral and GPIO pins are configured by the CubeMX device configuration tool.
 * @param serial Driver handle
 */
void initSerial(tSerial* serial)
{
    serial->send = (void (*)(tInterface*, uint8))sendSerial;
    serial->receive = (uint8 (*)(tInterface*))receiveSerial;
    serial->isReceiveDataAvailable = (uint8 (*)(tInterface*))isReceiveDataAvailable;
    serial->isSendReady = (uint8 (*)(tInterface*))isSendReady;
}

/**
 * This function adds 1 byte into the transmit buffer.
 * The USART peripheral will send the byte once the transmit buffer is empty (all previous bytes in buffer have been sent).
 * @param serial Driver handle
 * @param data Data byte
 */
static void sendSerial(tSerial* serial, uint8 data)
{
    HAL_UART_Transmit(&huart2, &data, 1U, X2C_UART_TIMEOUT);
}

/**
 * This function receives the next data byte from the USART receive buffer.
 * @param serial Driver handle
 * @returns Next received data byte
 */
static uint8 receiveSerial(tSerial* serial)
{
    uint8 data;
    HAL_UART_Receive(&huart2, &data, 1U, X2C_UART_TIMEOUT);
    return (data);
}

/**
 * This function checks if new data is available in the USART receive buffer.
 * If an Serial protocol error has occurred, the error flags are also cleared.
 * @param serial Driver handle
 * @retval 0 No data available
 * @retval 1 Data available
 */
static uint8 isReceiveDataAvailable(tSerial* serial)
{
    uint8 rxDataAvail;
    if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXFNE))
    {
        rxDataAvail = 1U;
    }
    else
    {
        rxDataAvail = 0U;
    }

    /* Check if Overrun, Noise, Framing or Parity error flag is set and clear them */
    if ((huart2.Instance->ISR & (USART_ISR_PE | USART_ISR_FE | USART_ISR_NE | USART_ISR_ORE)) != 0U)
    {
        /* Write to ICR register to clear all 4 error flags */
        huart2.Instance->ICR = USART_ICR_PECF | USART_ICR_FECF | USART_ICR_NECF | USART_ICR_ORECF;
    }

    return(rxDataAvail);
}

/**
 * This function checks if a new byte can be added to the USART transmit buffer.
 * @param serial Driver handle
 * @retval 0 Transmit buffer full / Not ready to add a new byte
 * @retval 1 Transmit buffer not full / Ready to add a new byte
 */
static uint8 isSendReady(tSerial* serial)
{
    uint8 sendReady;
    if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_TXFNF))
    {
        sendReady = 1U;
    }
    else
    {
        sendReady = 0U;
    }
    return(sendReady);
}

/**
 * @brief Routine to calculate temperature from internal temperature sensor.
 *
 * NOTE: Internal temperature sensor measurement is not very accurate.
 * Factory calibration has +/-10mV voltage reference tolerance and +/-5&deg;C temperature reference tolerance.
 * Additionally, linearity over temperature is specified with +/-2&deg;C.
 *
 * @param adcValue ADC result from internal temperature sensor channel
 * @return CPU temperature in degree Celsius
 */
float32 calculateCpuTemperature(int16 adcValue)
{
  int32 temp;

  temp = (((int32)adcValue * VDD_APPLI / VDD_CALIB)  - (int32)*TEMP30_CAL_ADDR);
  temp = temp * (int32)(130 - 30);
  temp = temp / (int32)(*TEMP130_CAL_ADDR - *TEMP30_CAL_ADDR);
  temp = temp + 30;

  return (float32)temp; /* temperature in degrees Celsius */
}
