
#include <stm32f1xx_hal.h>

UART_HandleTypeDef huart1;

// --- Function prototypes ---
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);

// --- Optional RX buffer for interrupt ---
uint8_t rx_byte;

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART1_UART_Init();

    char msg[] = "UART started at 38400 baud\r\n";

    // Send a startup message
    HAL_UART_Transmit(&huart1, (uint8_t*)msg, sizeof(msg)-1, HAL_MAX_DELAY);

    // Start interrupt-based receive of one byte
    HAL_UART_Receive_IT(&huart1, &rx_byte, 1);

    while (1)
    {
        // Send a heartbeat message every second
        char heartbeat[] = "Ping\r\n";
        HAL_UART_Transmit(&huart1, (uint8_t*)heartbeat, sizeof(heartbeat)-1, HAL_MAX_DELAY);

        HAL_Delay(1000);
    }
}

// -----------------------------------------------------------------------------
// Error handler
// -----------------------------------------------------------------------------
void Error_Handler(void)
{
    while (1) { }
}


// -----------------------------------------------------------------------------
// UART1 initialization (38400 baud)
// -----------------------------------------------------------------------------
static void MX_USART1_UART_Init(void)
{
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 38400;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;

    if (HAL_UART_Init(&huart1) != HAL_OK)
    {
        Error_Handler();
    }
}

// -----------------------------------------------------------------------------
// GPIO for UART1 pins (PA9 TX, PA10 RX)
// -----------------------------------------------------------------------------
static void MX_GPIO_Init(void)
{
    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // PA9 -> USART1_TX (Alternate Function Push-Pull)
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // PA10 -> USART1_RX (Input)
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

// -----------------------------------------------------------------------------
// Interrupt callback for UART receive
// -----------------------------------------------------------------------------
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART1) {

        // Echo received byte back
        HAL_UART_Transmit(&huart1, &rx_byte, 1, HAL_MAX_DELAY);

        // Re-enable reception of next byte
        HAL_UART_Receive_IT(&huart1, &rx_byte, 1);
    }
}

// -----------------------------------------------------------------------------
// Basic system clock (HSE not required for 38400 UART)
// -----------------------------------------------------------------------------
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK |
                                  RCC_CLOCKTYPE_SYSCLK |
                                  RCC_CLOCKTYPE_PCLK1 |
                                  RCC_CLOCKTYPE_PCLK2;

    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
}

