/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2026 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdint.h>
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define ROWS        7
#define COLS        96
#define NUM_CHIPS   12       /* 12 x 8 bits = 96 column bits */
#define ROW_DWELL   500      /* microseconds per row — tune for flicker/ghosting */
#define UART_BUF    128
#define WIDE_COLS   512      /* pre-render buffer width */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi1;
UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */

/* Row pin lookup — matches CubeMX GPIO labels */
typedef struct { GPIO_TypeDef *port; uint16_t pin; } RowPin;
static const RowPin ROW_PINS[ROWS] = {
    {ROW_0_GPIO_Port, ROW_0_Pin},   /* ROW_0 — PB0 */
    {ROW_1_GPIO_Port, ROW_1_Pin},   /* ROW_1 — PA0 */
    {ROW_2_GPIO_Port, ROW_2_Pin},   /* ROW_2 — PA1 */
    {ROW_3_GPIO_Port, ROW_3_Pin},   /* ROW_3 — PB4 */
    {ROW_4_GPIO_Port, ROW_4_Pin},   /* ROW_4 — PB5 */
    {ROW_5_GPIO_Port, ROW_5_Pin},   /* ROW_5 — PA11 */
    {ROW_6_GPIO_Port, ROW_6_Pin},   /* ROW_6 — PA8 */
};

/* Framebuffer — fb[row][chip], each byte = 8 column bits */
static uint8_t fb[ROWS][NUM_CHIPS];

/* Pre-rendered wide scroll buffer */
static uint8_t  wide[ROWS][WIDE_COLS];
static uint16_t wide_cols  = 0;   /* 0 = no message yet, display stays blank */
static int32_t  scroll_x   = 0;

/* UART receive */
static uint8_t  uart_rx_byte;
static char     uart_buf[UART_BUF];
static uint8_t  uart_idx    = 0;
static uint8_t  new_message = 0;
static char     message[UART_BUF] = "";



/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
static void MX_USART2_UART_Init(void);

/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* 5x7 font, ASCII 32-90
   Each glyph = 5 bytes (columns), bit0 = top row */
static const uint8_t FONT[][5] = {
    {0x00,0x00,0x00,0x00,0x00}, /* ' ' 32 */
    {0x00,0x00,0x5F,0x00,0x00}, /* '!' */
    {0x00,0x07,0x00,0x07,0x00}, /* '"' */
    {0x14,0x7F,0x14,0x7F,0x14}, /* '#' */
    {0x24,0x2A,0x7F,0x2A,0x12}, /* '$' */
    {0x23,0x13,0x08,0x64,0x62}, /* '%' */
    {0x36,0x49,0x55,0x22,0x50}, /* '&' */
    {0x00,0x05,0x03,0x00,0x00}, /* ''' */
    {0x00,0x1C,0x22,0x41,0x00}, /* '(' */
    {0x00,0x41,0x22,0x1C,0x00}, /* ')' */
    {0x08,0x2A,0x1C,0x2A,0x08}, /* '*' */
    {0x08,0x08,0x3E,0x08,0x08}, /* '+' */
    {0x00,0x50,0x30,0x00,0x00}, /* ',' */
    {0x08,0x08,0x08,0x08,0x08}, /* '-' */
    {0x00,0x60,0x60,0x00,0x00}, /* '.' */
    {0x20,0x10,0x08,0x04,0x02}, /* '/' */
    {0x3E,0x51,0x49,0x45,0x3E}, /* '0' */
    {0x00,0x42,0x7F,0x40,0x00}, /* '1' */
    {0x42,0x61,0x51,0x49,0x46}, /* '2' */
    {0x21,0x41,0x45,0x4B,0x31}, /* '3' */
    {0x18,0x14,0x12,0x7F,0x10}, /* '4' */
    {0x27,0x45,0x45,0x45,0x39}, /* '5' */
    {0x3C,0x4A,0x49,0x49,0x30}, /* '6' */
    {0x01,0x71,0x09,0x05,0x03}, /* '7' */
    {0x36,0x49,0x49,0x49,0x36}, /* '8' */
    {0x06,0x49,0x49,0x29,0x1E}, /* '9' */
    {0x00,0x36,0x36,0x00,0x00}, /* ':' */
    {0x00,0x56,0x36,0x00,0x00}, /* ';' */
    {0x00,0x08,0x14,0x22,0x41}, /* '<' */
    {0x14,0x14,0x14,0x14,0x14}, /* '=' */
    {0x41,0x22,0x14,0x08,0x00}, /* '>' */
    {0x02,0x01,0x51,0x09,0x06}, /* '?' */
    {0x32,0x49,0x79,0x41,0x3E}, /* '@' */
    {0x7E,0x09,0x09,0x09,0x7E}, /* 'A' */
    {0x7F,0x49,0x49,0x49,0x36}, /* 'B' */
    {0x3E,0x41,0x41,0x41,0x22}, /* 'C' */
    {0x7F,0x41,0x41,0x41,0x3E}, /* 'D' */
    {0x7F,0x49,0x49,0x49,0x41}, /* 'E' */
    {0x7F,0x09,0x09,0x09,0x01}, /* 'F' */
    {0x3E,0x41,0x49,0x49,0x7A}, /* 'G' */
    {0x7F,0x08,0x08,0x08,0x7F}, /* 'H' */
    {0x41,0x7F,0x41,0x00,0x00}, /* 'I' */
    {0x20,0x40,0x41,0x3F,0x01}, /* 'J' */
    {0x7F,0x08,0x14,0x22,0x41}, /* 'K' */
    {0x7F,0x40,0x40,0x40,0x40}, /* 'L' */
    {0x7F,0x02,0x04,0x02,0x7F}, /* 'M' */
    {0x7F,0x04,0x08,0x10,0x7F}, /* 'N' */
    {0x3E,0x41,0x41,0x41,0x3E}, /* 'O' */
    {0x7F,0x09,0x09,0x09,0x06}, /* 'P' */
    {0x3E,0x41,0x51,0x21,0x5E}, /* 'Q' */
    {0x7F,0x09,0x19,0x29,0x46}, /* 'R' */
    {0x46,0x49,0x49,0x49,0x31}, /* 'S' */
    {0x01,0x01,0x7F,0x01,0x01}, /* 'T' */
    {0x3F,0x40,0x40,0x40,0x3F}, /* 'U' */
    {0x1F,0x20,0x40,0x20,0x1F}, /* 'V' */
    {0x7F,0x20,0x10,0x20,0x7F}, /* 'W' */
    {0x63,0x14,0x08,0x14,0x63}, /* 'X' */
    {0x03,0x04,0x78,0x04,0x03}, /* 'Y' */
    {0x61,0x51,0x49,0x45,0x43}, /* 'Z' */
};

/* ── Microsecond busy-wait using DWT cycle counter ── */
static void delay_us(uint32_t us)
{
    uint32_t start = DWT->CYCCNT;
    uint32_t ticks = (SystemCoreClock / 1000000U) * us;
    while ((DWT->CYCCNT - start) < ticks);
}

/* ── Turn all row pins off (HIGH = ULN2803A pulls gate low = MOSFET off) ── */
static void all_rows_off(void)
{
    for (int i = 0; i < ROWS; i++)
        HAL_GPIO_WritePin(ROW_PINS[i].port, ROW_PINS[i].pin, GPIO_PIN_SET);
}

/* ── Send one row of column data via SPI then enable that row ── */
static void display_refresh(void)
{
    for (int row = 0; row < ROWS; row++) {
        all_rows_off();
        HAL_SPI_Transmit(&hspi1, fb[row], NUM_CHIPS, HAL_MAX_DELAY);
        /* LOW = ULN2803A releases gate = MOSFET on = row enabled */
        HAL_GPIO_WritePin(ROW_PINS[row].port, ROW_PINS[row].pin, GPIO_PIN_RESET);
        delay_us(ROW_DWELL);
    }
    all_rows_off();
}

/* ── Render message string into wide[] pixel buffer ── */
static void render_message(const char *msg)
{
    memset(wide, 0, sizeof(wide));
    uint16_t col = COLS;   /* lead with one blank screen so text scrolls in */

    while (*msg && col < (WIDE_COLS - 6)) {
        uint8_t c = (uint8_t)*msg++;
        /* Convert lowercase to uppercase */
        if (c >= 'a' && c <= 'z') c -= 32;
        if (c >= 32 && c <= 90) {
            const uint8_t *glyph = FONT[c - 32];
            for (int g = 0; g < 5 && col < WIDE_COLS; g++, col++) {
                for (int row = 0; row < ROWS; row++) {
                    wide[row][col] = (glyph[g] >> row) & 1;
                }
            }
        }
        col++;   /* one gap column between characters */
    }
    wide_cols = col + COLS;   /* scroll until text fully exits left edge */
    scroll_x  = 0;
}

/* ── Copy current scroll window from wide[] into fb[][] ── */
static void update_fb_from_scroll(void)
{
    for (int row = 0; row < ROWS; row++) {
        memset(fb[row], 0, NUM_CHIPS);
        for (int col = 0; col < COLS; col++) {
            uint16_t src = (uint16_t)(scroll_x + col);
            if (src < WIDE_COLS && wide[row][src]) {
                int chip =  col / 8;
                int bit  =  7 - (col % 8);
                fb[row][chip] |= (uint8_t)(1 << bit);
            }
        }
    }
}

/* ── Arrive north star pixel map, 7 rows x 11 cols ── */
static const uint8_t STAR[7][11] = {
    {0,0,0,0,1,0,0,0,0,0,0},
    {0,0,0,1,1,1,0,0,0,0,0},
    {1,1,0,0,1,0,0,1,1,1,1},
    {1,1,1,1,1,1,1,1,1,1,1},
    {1,1,0,0,1,0,0,1,1,1,1},
    {0,0,0,1,1,1,0,0,0,0,0},
    {0,0,0,0,1,0,0,0,0,0,0},
};

/* ARRIVE — 6 chars, each 5 cols wide + 1 col gap = 36 cols total
   Rows 0-6, col order left to right: A R R I V E */
static const uint8_t ARRIVE_GLYPH[7][36] = {
/*         A              R              R              I              V              E        */
/* r0 */ {0,1,1,1,0,0,  0,1,1,1,0,0,  0,1,1,1,0,0,  0,1,1,1,0,0,  1,0,0,0,1,0,  1,1,1,1,1,0},
/* r1 */ {1,0,0,0,1,0,  1,0,0,0,1,0,  1,0,0,0,1,0,  0,0,1,0,0,0,  1,0,0,0,1,0,  1,0,0,0,0,0},
/* r2 */ {1,0,0,0,1,0,  1,0,0,0,1,0,  1,0,0,0,1,0,  0,0,1,0,0,0,  1,0,0,0,1,0,  1,0,0,0,0,0},
/* r3 */ {1,1,1,1,1,0,  1,1,1,1,0,0,  1,1,1,1,0,0,  0,0,1,0,0,0,  0,1,0,1,0,0,  1,1,1,1,0,0},
/* r4 */ {1,0,0,0,1,0,  1,0,1,0,0,0,  1,0,1,0,0,0,  0,0,1,0,0,0,  0,1,0,1,0,0,  1,0,0,0,0,0},
/* r5 */ {1,0,0,0,1,0,  1,0,0,1,0,0,  1,0,0,1,0,0,  0,0,1,0,0,0,  0,0,1,0,0,0,  1,0,0,0,0,0},
/* r6 */ {1,0,0,0,1,0,  1,0,0,0,1,0,  1,0,0,0,1,0,  0,1,1,1,0,0,  0,0,1,0,0,0,  1,1,1,1,1,0},
};

/* ── Render logo into fb
      mask_col: columns < mask_col are hidden (wipe reveals right-to-left), -1 = show all ── */
static void render_logo(int star_col, int text_col, int mask_col)
{
    memset(fb, 0, sizeof(fb));

    /* Draw star */
    for (int row = 0; row < 7; row++) {
        for (int sc = 0; sc < 11; sc++) {
            int col = star_col + sc;
            if (col >= 0 && col < COLS && STAR[row][sc]) {
                if (mask_col < 0 || col >= mask_col) {
                    int chip = col / 8;
                    int bit  = 7 - (col % 8);
                    fb[row][chip] |= (uint8_t)(1 << bit);
                }
            }
        }
    }

    /* Draw ARRIVE text */
    for (int row = 0; row < 7; row++) {
        for (int tc = 0; tc < 36; tc++) {
            int col = text_col + tc;
            if (col >= 0 && col < COLS && ARRIVE_GLYPH[row][tc]) {
                if (mask_col < 0 || col >= mask_col) {
                    int chip = col / 8;
                    int bit  = 7 - (col % 8);
                    fb[row][chip] |= (uint8_t)(1 << bit);
                }
            }
        }
    }
}

/* ── Blank fb but keep specific rows lit (bitmask) ── */
static void render_logo_rows(int star_col, int text_col, uint8_t row_mask)
{
    memset(fb, 0, sizeof(fb));
    for (int row = 0; row < 7; row++) {
        if (!(row_mask & (1 << row))) continue;
        for (int sc = 0; sc < 11; sc++) {
            int col = star_col + sc;
            if (col >= 0 && col < COLS && STAR[row][sc]) {
                int chip = col / 8; int bit = 7 - (col % 8);
                fb[row][chip] |= (uint8_t)(1 << bit);
            }
        }
        for (int tc = 0; tc < 30; tc++) {
            int col = text_col + tc;
            if (col >= 0 && col < COLS && ARRIVE_GLYPH[row][tc]) {
                int chip = col / 8; int bit = 7 - (col % 8);
                fb[row][chip] |= (uint8_t)(1 << bit);
            }
        }
    }
}

/* ── Refresh for a given number of milliseconds ── */
static void refresh_for(uint32_t ms)
{
    uint32_t t = HAL_GetTick();
    while ((HAL_GetTick() - t) < ms) { display_refresh(); }
}

/* ── Arrive boot animation ── */
static void arrive_animation(void)
{
    /* Logo layout — text LEFT, star RIGHT:
       ARRIVE = 36 cols, gap = 2, star = 11 cols → total = 49 cols
       centred on 96: start = (96 - 49) / 2 = 23
       text_col = 23, star_col = 23 + 36 + 2 = 61 */
    const int text_col = 23;
    const int star_col = 61;

    /* ── Phase 1: Star builds from centre outward ── */
    /* Frame 1 — just centre cross */
    memset(fb, 0, sizeof(fb));
    for (int row = 0; row < 7; row++) {
        int col = star_col + 4;   /* centre column of star */
        int chip = col / 8; int bit = 7 - (col % 8);
        fb[row][chip] |= (uint8_t)(1 << bit);
    }
    /* horizontal bar centre */
    for (int sc = 3; sc <= 5; sc++) {
        int col = star_col + sc;
        int chip = col / 8; int bit = 7 - (col % 8);
        fb[3][chip] |= (uint8_t)(1 << bit);
    }
    refresh_for(120);

    /* Frame 2 — inner star shape */
    memset(fb, 0, sizeof(fb));
    for (int row = 0; row < 7; row++) {
        for (int sc = 3; sc <= 7; sc++) {
            if (STAR[row][sc]) {
                int col = star_col + sc;
                int chip = col / 8; int bit = 7 - (col % 8);
                fb[row][chip] |= (uint8_t)(1 << bit);
            }
        }
    }
    refresh_for(120);

    /* Frame 3 — full star, text still hidden */
    render_logo(star_col, text_col, star_col);  /* mask hides everything left of star */
    refresh_for(150);

    /* ── Phase 2: Glint pulse ── */
    memset(fb, 0, sizeof(fb));
    refresh_for(80);
    render_logo(star_col, text_col, star_col);
    refresh_for(80);
    memset(fb, 0, sizeof(fb));
    refresh_for(60);
    render_logo(star_col, text_col, star_col);
    refresh_for(100);

    /* ── Phase 3: Wipe right-to-left — reveal ARRIVE sweeping from star leftward ── */
    for (int mask = star_col; mask >= text_col - 1; mask -= 2) {
        render_logo(star_col, text_col, mask);
        refresh_for(18);
    }
    render_logo(star_col, text_col, -1);
    refresh_for(18);

    /* ── Phase 4: Hold ── */
    refresh_for(2000);

    /* ── Phase 5: Fade out — rows extinguish top+bottom inward ── */
    /* Order: 0,6 then 1,5 then 2,4 then 3 */
    uint8_t row_mask = 0x7F;   /* all 7 rows on */

    row_mask &= ~(1 << 0); row_mask &= ~(1 << 6);
    render_logo_rows(star_col, text_col, row_mask); refresh_for(80);

    row_mask &= ~(1 << 1); row_mask &= ~(1 << 5);
    render_logo_rows(star_col, text_col, row_mask); refresh_for(80);

    row_mask &= ~(1 << 2); row_mask &= ~(1 << 4);
    render_logo_rows(star_col, text_col, row_mask); refresh_for(80);

    row_mask &= ~(1 << 3);
    memset(fb, 0, sizeof(fb)); refresh_for(80);

    /* Brief blank before scroll */
    refresh_for(200);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART2) {
        char b = (char)uart_rx_byte;
        if (b == '\n' || b == '\r') {
            if (uart_idx > 0) {
                uart_buf[uart_idx] = '\0';
                memcpy(message, uart_buf, uart_idx + 1);
                uart_idx    = 0;
                new_message = 1;
            }
        } else if (uart_idx < UART_BUF - 1) {
            uart_buf[uart_idx++] = b;
        }
        /* Re-arm for next byte */
        HAL_UART_Receive_IT(&huart2, &uart_rx_byte, 1);
    }
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  MX_GPIO_Init();
  MX_SPI1_Init();
  MX_USART2_UART_Init();

  /* USER CODE BEGIN 2 */

  /* Enable DWT cycle counter for microsecond delays */
  CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
  DWT->CYCCNT = 0;
  DWT->CTRL  |= DWT_CTRL_CYCCNTENA_Msk;

  /* All rows off, blank display */
  all_rows_off();
  memset(fb, 0, sizeof(fb));

  /* Start UART receive interrupt */
  HAL_UART_Receive_IT(&huart2, &uart_rx_byte, 1);

  /* Render default message */
  render_message(message);
  update_fb_from_scroll();

  /* USER CODE END 2 */

  /* USER CODE BEGIN WHILE */

  /* Run boot animation */
  arrive_animation();

  update_fb_from_scroll();

  uint32_t last_scroll = HAL_GetTick();
  const uint32_t scroll_ms = 40;

  while (1)
  {
    if (new_message) {
        new_message = 0;
        render_message(message);
    }

    if ((HAL_GetTick() - last_scroll) >= scroll_ms) {
        last_scroll = HAL_GetTick();
        scroll_x++;
        if (scroll_x >= wide_cols) {
            /* End of message — switch to next */
            scroll_x = 0;
        }
        update_fb_from_scroll();
    }

    display_refresh();

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV4;
  RCC_OscInitStruct.PLL.PLLN = 85;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief SPI1 Initialization Function
  */
static void MX_SPI1_Init(void)
{
  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 7;
  hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */
}

/**
  * @brief USART2 Initialization Function
  */
static void MX_USART2_UART_Init(void)
{
  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetTxFifoThreshold(&huart2, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetRxFifoThreshold(&huart2, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_DisableFifoMode(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */
}

/**
  * @brief GPIO Initialization Function
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  /* USER CODE BEGIN MX_GPIO_Init_1 */

  /* USER CODE END MX_GPIO_Init_1 */

  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  HAL_GPIO_WritePin(GPIOA, ROW_1_Pin|ROW_2_Pin|ROW_6_Pin|ROW_5_Pin, GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIOB, ROW_0_Pin|ROW_3_Pin|ROW_4_Pin|LED_Pin, GPIO_PIN_SET);

  GPIO_InitStruct.Pin = ROW_1_Pin|ROW_2_Pin|ROW_6_Pin|ROW_5_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = ROW_0_Pin|ROW_3_Pin|ROW_4_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = LED_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);

  /* USER CODE BEGIN MX_GPIO_Init_2 */

  /* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
