/* Correction du TP 5 (partie 1, sans OS) -- extraits de Core/Src/main.c.
 *
 * Configuration CubeMX : UART5 Asynchronous sur PB12 (RX) / PB13 (TX),
 * 115200 8N1, interruption UART5 cochee dans le NVIC (etape 3, 2e partie) ;
 * LED_1..LED_4 en sortie ; SYS Debug = Serial Wire ; horloge HSI par defaut.
 */

/* ===== USER CODE BEGIN Includes ============================================= */
#include <stdio.h>
/* USER CODE END Includes */

/* ===== USER CODE BEGIN PV =================================================== */
typedef struct { GPIO_TypeDef *port; uint16_t pin; } led_t;

static const led_t leds[4] = {
    { LED_1_GPIO_Port, LED_1_Pin },
    { LED_2_GPIO_Port, LED_2_Pin },
    { LED_3_GPIO_Port, LED_3_Pin },
    { LED_4_GPIO_Port, LED_4_Pin },
};

static uint8_t          rx;            /* octet recu par interruption */
static volatile uint8_t rx_ready;      /* 1 : rx contient un caractere */
/* USER CODE END PV */

/* ===== USER CODE BEGIN 0 ==================================================== */
int __io_putchar(int ch)
{
    uint8_t c = (uint8_t)ch;

    HAL_UART_Transmit(&huart5, &c, 1u, 10u);
    return ch;
}

static void handle_char(uint8_t c)
{
    HAL_UART_Transmit(&huart5, &c, 1u, 10u);          /* echo */
    if ((c >= (uint8_t)'1') && (c <= (uint8_t)'4'))
    {
        uint32_t k = (uint32_t)(c - (uint8_t)'1');
        HAL_GPIO_TogglePin(leds[k].port, leds[k].pin);
    }
}
/* USER CODE END 0 */

/* ===== USER CODE BEGIN 2 ====================================================
    HAL_UART_Receive_IT(&huart5, &rx, 1u);     (etape 3, 2e partie seulement)
   USER CODE END 2 */

/* ===== Dans while (1), USER CODE BEGIN 3 ====================================
 * Une seule des variantes ci-dessous a la fois. */

/* Etape 1 : une ligne par seconde. */
#if 0
    {
        static const char msg[] = "Bonjour depuis la carte\r\n";

        HAL_UART_Transmit(&huart5, (const uint8_t *)msg, (uint16_t)(sizeof(msg) - 1u), 100u);
        HAL_Delay(1000);
    }
#endif

/* Etape 2 : printf. */
#if 0
    {
        static uint32_t n = 0u;

        printf("compteur = %lu\r\n", (unsigned long)n++);
        HAL_Delay(1000);
    }
#endif

/* Etape 3, scrutation : touches 1 a 4, echo. */
#if 0
    {
        uint8_t c;

        if (HAL_UART_Receive(&huart5, &c, 1u, 10u) == HAL_OK)
        {
            handle_char(c);
        }
    }
#endif

/* Etape 3, interruption : le caractere est traite hors de l'interruption ;
 * LED_4 clignote sans s'arreter. */
#if 1
    {
        static uint32_t last = 0u;

        if (rx_ready)
        {
            uint8_t c = rx;

            rx_ready = 0u;
            HAL_UART_Receive_IT(&huart5, &rx, 1u);    /* relance (question 5) */
            handle_char(c);
        }
        if ((HAL_GetTick() - last) >= 250u)
        {
            last = HAL_GetTick();
            HAL_GPIO_TogglePin(LED_4_GPIO_Port, LED_4_Pin);
        }
    }
#endif
/* USER CODE END 3 */

/* ===== USER CODE BEGIN 4 ==================================================== */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == UART5)
    {
        rx_ready = 1u;      /* traitement dans la boucle : interruption courte */
    }
}
/* USER CODE END 4 */

/* Reponses attendues aux questions :
 *  1. \n descend d'une ligne, \r revient en debut de ligne : sans \r, le
 *     texte part en escalier dans la plupart des terminaux.
 *  2. 25 caracteres x 10 bits / 115200 = 2,2 ms.
 *  3. Des caracteres sans rapport (debit different : les bits sont mal
 *     echantillonnes).
 *  4. Scrutation : des caracteres perdus (un seul octet de reception ; ceux
 *     qui arrivent pendant le reste de la boucle ecrasent ou debordent).
 *     Interruption : bien mieux, mais un seul caractere a la fois ; pour une
 *     longue chaine il faut un tampon (exercice du tampon circulaire) ou le
 *     DMA (partie 2).
 *  5. HAL_UART_Receive_IT ne recoit que le nombre d'octets demande, puis
 *     s'arrete : il faut redemander le suivant.
 */
