/* Correction du TP 6 (partie 1, sans OS) -- extraits de Core/Src/main.c.
 *
 * Configuration CubeMX : PB0 = ADC2_INP9 (IN9 single-ended), 16 bits,
 * Rank 1 Sampling Time 64.5 cycles, Clock Prescaler async /4 ; ADC Clock Mux
 * = CKPER (HSI 64 MHz) ; LED_1..LED_4 en sortie (PD4, PD3, PD2, PC7) ;
 * SYS Debug = Serial Wire ; horloge HSI par defaut.
 *
 * Valeurs de la carte (mesurees a la mise en service) : rapport du pont 0,25
 * (30 k serie, 10 k vers GND -- le SCHEMA indique l'inverse, il est faux).
 */

/* ===== USER CODE BEGIN PD =================================================== */
#define VREF_MV        3300u
#define ADC_FULL       65535u
#define DIVIDER        4u          /* (30 k + 10 k) / 10 k */
#define VBAT_EMPTY_MV  9600u       /* 3 x 3,2 V : seuil critique */
#define VBAT_FULL_MV   12600u      /* 3 x 4,2 V : pleine charge  */
/* USER CODE END PD */

/* ===== 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 },
};

/* Visibles dans « Live Expressions » du debogueur. */
volatile uint32_t g_adc_raw;
volatile uint32_t g_vbat_mV;
volatile uint32_t g_pct;
/* USER CODE END PV */

/* ===== USER CODE BEGIN 0 ==================================================== */
static uint32_t adc_read(void)
{
    uint32_t v = 0u;

    HAL_ADC_Start(&hadc2);
    if (HAL_ADC_PollForConversion(&hadc2, 10u) == HAL_OK)
    {
        v = HAL_ADC_GetValue(&hadc2);
    }
    HAL_ADC_Stop(&hadc2);
    return v;
}

/* Entiers seulement : 65535 x 3300 x 4 tient sur 32 bits (8,7e8 < 4,3e9). */
static uint32_t vbat_mV(uint32_t raw)
{
    return (raw * VREF_MV * DIVIDER) / ADC_FULL;
}

static uint32_t percent(uint32_t mv)
{
    if (mv <= VBAT_EMPTY_MV) { return 0u; }
    if (mv >= VBAT_FULL_MV)  { return 100u; }
    return ((mv - VBAT_EMPTY_MV) * 100u) / (VBAT_FULL_MV - VBAT_EMPTY_MV);
}

/* Jauge : n LED allumees, n = 1 par tranche de 25 % entamee au-dela de 0. */
static void gauge(uint32_t pct)
{
    uint32_t n = (pct + 24u) / 25u;      /* 0, 1..25 -> 1, ..., 76..100 -> 4 */

    for (uint32_t k = 0u; k < 4u; k++)
    {
        HAL_GPIO_WritePin(leds[k].port, leds[k].pin,
                          (k < n) ? GPIO_PIN_SET : GPIO_PIN_RESET);
    }
}
/* USER CODE END 0 */

/* ===== USER CODE BEGIN 2 ====================================================
    HAL_ADCEx_Calibration_Start(&hadc2, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
   USER CODE END 2 */

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

/* Etape 2 : mesure toutes les 500 ms, lue au debogueur. */
#if 0
    g_adc_raw = adc_read();
    g_vbat_mV = vbat_mV(g_adc_raw);
    HAL_Delay(500);
#endif

/* Etape 3 : pourcentage, jauge, clignotement sous 20 %. */
#if 1
    {
        static uint32_t blink = 0u;

        g_adc_raw = adc_read();
        g_vbat_mV = vbat_mV(g_adc_raw);
        g_pct     = percent(g_vbat_mV);

        if (g_pct < 20u)
        {
            gauge(0u);
            blink ^= 1u;
            HAL_GPIO_WritePin(LED_1_GPIO_Port, LED_1_Pin,
                              blink ? GPIO_PIN_SET : GPIO_PIN_RESET);
        }
        else
        {
            gauge(g_pct);
        }
        HAL_Delay(500);
    }
#endif
/* USER CODE END 3 */

/* Reponses attendues aux questions :
 *  1. 12 V x 0,75 = 9 V sur PB0 : bien au-dela des 3,3 V admissibles ; la
 *     broche (et ses diodes de protection, puis VDD) recoit un courant qui
 *     peut detruire le microcontroleur.
 *  2. 64,5 / 16 MHz = 4,0 us, environ cinq fois les 0,8 us necessaires.
 *     (Le reglage par defaut, 1,5 cycle, ne donnerait que 0,1 us.)
 *  3. A la mise en service : ecart de -0,1 % a +0,25 % (tolerance des
 *     resistances a 1 % et Vref reelle un peu sous 3,3 V).
 *  4. Non : quelques unites de bruit sur les bits de poids faible ; moyenner
 *     plusieurs mesures (ou utiliser le sur-echantillonnage materiel de l'ADC).
 *  5. La jauge lineaire reste longtemps vers 50-70 % puis chute vite en fin
 *     de decharge ; une table tension -> pourcentage suit mieux la courbe.
 *  6. Resistance interne de la batterie et des cables : la tension baisse
 *     sous charge (U = E - R I). Moyenner, et ajouter une hysteresis.
 */
