/* Correction du TP 7 (partie 1, sans OS) -- extraits de Core/Src/main.c.
 *
 * Configuration CubeMX : I2C2 sur PB10 (SCL) / PB11 (SDA), I2C3 sur PA8 (SCL)
 * / PC9 (SDA), Standard Mode 100 kHz ; SYS Debug = Serial Wire ; horloge HSI
 * par defaut. Valeurs relevees sur la carte a la mise en service : TMP102 en
 * 0x48 (config 0x60A0, ~28,6 degC au repos) ; LSM6DSOX WHO_AM_I = 0x6C.
 */

/* ===== USER CODE BEGIN PD =================================================== */
#define TMP102_ADDR     (0x48u << 1)
#define TMP102_TEMP     0x00u
#define TMP102_CONFIG   0x01u

#define IMU_WHO_AM_I    0x0Fu
#define IMU_CTRL1_XL    0x10u
#define IMU_CTRL2_G     0x11u
#define IMU_CTRL3_C     0x12u
#define IMU_OUTX_L_G    0x22u
#define IMU_OUTX_L_A    0x28u
#define I2C_TIMEOUT_MS  5u
/* USER CODE END PD */

/* ===== USER CODE BEGIN PV =================================================== */
/* Visibles dans « Live Expressions » du debogueur. */
volatile uint8_t  g_found[16];          /* adresses qui acquittent sur I2C2 */
volatile uint32_t g_found_count;
volatile uint16_t g_tmp_config;         /* attendu : 0x60A0 */
volatile int32_t  g_temp_mC;
volatile uint16_t g_imu_addr;           /* adresse HAL retenue, 0 si absente */
volatile uint8_t  g_who_am_i;           /* attendu : 0x6C */
volatile int32_t  g_acc_mg[3];
volatile int32_t  g_gyro_mdps[3];
/* USER CODE END PV */

/* ===== USER CODE BEGIN 0 ==================================================== */
/* Etape 1 : balayage du bus I2C2. */
static void i2c2_scan(void)
{
    g_found_count = 0u;
    for (uint16_t a = 1u; a < 128u; a++)
    {
        if (HAL_I2C_IsDeviceReady(&hi2c2, (uint16_t)(a << 1), 2u, I2C_TIMEOUT_MS) == HAL_OK)
        {
            if (g_found_count < 16u) { g_found[g_found_count] = (uint8_t)a; }
            g_found_count++;
        }
    }
}

/* Lit un registre 16 bits du TMP102, octet de poids fort en premier. */
static int tmp102_read16(uint8_t reg, uint16_t *out)
{
    uint8_t b[2];

    if (HAL_I2C_Mem_Read(&hi2c2, TMP102_ADDR, reg, I2C_MEMADD_SIZE_8BIT,
                         b, 2u, I2C_TIMEOUT_MS) != HAL_OK)
    {
        return 0;
    }
    *out = (uint16_t)(((uint16_t)b[0] << 8) | b[1]);
    return 1;
}

/* Etape 3 : 12 bits cadres a gauche, complement a deux, 62,5 m degC par pas. */
static int tmp102_temp_mC(int32_t *out)
{
    uint16_t raw16;
    int32_t  raw;

    if (!tmp102_read16(TMP102_TEMP, &raw16)) { return 0; }
    raw = (int32_t)(raw16 >> 4);
    if (raw & 0x800) { raw -= 4096; }          /* extension de signe */
    *out = (raw * 625) / 10;
    return 1;
}

/* Etape 4 : la centrale inertielle sur I2C3. */
static int imu_init(void)
{
    static const uint16_t addrs[2] = { 0x6Au << 1, 0x6Bu << 1 };
    uint8_t v;

    g_imu_addr = 0u;
    for (uint32_t k = 0u; k < 2u; k++)
    {
        if (HAL_I2C_IsDeviceReady(&hi2c3, addrs[k], 2u, I2C_TIMEOUT_MS) == HAL_OK)
        {
            g_imu_addr = addrs[k];
            break;
        }
    }
    if (g_imu_addr == 0u) { return 0; }

    if (HAL_I2C_Mem_Read(&hi2c3, g_imu_addr, IMU_WHO_AM_I, I2C_MEMADD_SIZE_8BIT,
                         &v, 1u, I2C_TIMEOUT_MS) != HAL_OK) { return 0; }
    g_who_am_i = v;
    if (v != 0x6Cu) { return 0; }

    v = 0x44u;   /* BDU + IF_INC : en premier, avant de lancer les mesures */
    HAL_I2C_Mem_Write(&hi2c3, g_imu_addr, IMU_CTRL3_C, I2C_MEMADD_SIZE_8BIT, &v, 1u, I2C_TIMEOUT_MS);
    v = 0x48u;   /* accelerometre 104 Hz, +/-4 g */
    HAL_I2C_Mem_Write(&hi2c3, g_imu_addr, IMU_CTRL1_XL, I2C_MEMADD_SIZE_8BIT, &v, 1u, I2C_TIMEOUT_MS);
    v = 0x40u;   /* gyroscope 104 Hz, 250 dps */
    HAL_I2C_Mem_Write(&hi2c3, g_imu_addr, IMU_CTRL2_G, I2C_MEMADD_SIZE_8BIT, &v, 1u, I2C_TIMEOUT_MS);
    return 1;
}

/* Trois axes de 16 bits, octet de poids faible en premier. */
static int imu_read3(uint8_t reg, int16_t out[3])
{
    uint8_t b[6];

    if (HAL_I2C_Mem_Read(&hi2c3, g_imu_addr, reg, I2C_MEMADD_SIZE_8BIT,
                         b, 6u, I2C_TIMEOUT_MS) != HAL_OK) { return 0; }
    for (uint32_t k = 0u; k < 3u; k++)
    {
        out[k] = (int16_t)(((uint16_t)b[2u * k + 1u] << 8) | b[2u * k]);
    }
    return 1;
}
/* USER CODE END 0 */

/* ===== USER CODE BEGIN 2 ====================================================
    i2c2_scan();
    { uint16_t c; if (tmp102_read16(TMP102_CONFIG, &c)) { g_tmp_config = c; } }
    (void)imu_init();
   USER CODE END 2 */

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

/* Etape 3 : la temperature, toutes les secondes. */
#if 0
    {
        int32_t t;

        if (tmp102_temp_mC(&t)) { g_temp_mC = t; }
        HAL_Delay(1000);
    }
#endif

/* Etape 4 : accelerometre (mg) et gyroscope (m deg/s), dix fois par seconde.
 * 0,122 mg/pas = 122 / 1000 ; 8,75 m deg/s/pas = 875 / 100. */
#if 1
    {
        int16_t a[3], g[3];
        int32_t t;

        if (tmp102_temp_mC(&t)) { g_temp_mC = t; }
        if ((g_imu_addr != 0u) && imu_read3(IMU_OUTX_L_A, a) && imu_read3(IMU_OUTX_L_G, g))
        {
            for (uint32_t k = 0u; k < 3u; k++)
            {
                g_acc_mg[k]    = ((int32_t)a[k] * 122) / 1000;
                g_gyro_mdps[k] = ((int32_t)g[k] * 875) / 100;
            }
        }
        HAL_Delay(100);
    }
#endif
/* USER CODE END 3 */

/* Reponses attendues aux questions :
 *  1. 0x48 (TMP102) sur une carte seule ; sur un robot complet, aussi le
 *     capteur de distance avant (VL53L5CX, 0x29) sur I2C2.
 *  2. On interroge l'adresse divisee par deux : personne ne repond (ou un
 *     autre composant, par hasard).
 *  3. Vers 28 degC au repos (mesure a la mise en service : 28,6 degC) : la
 *     carte et le microcontroleur chauffent ; le TMP102 mesure sa propre
 *     temperature, pas celle de l'air.
 *  4. Quelques dixiemes de degre en quelques secondes (+0,5 degC releve) :
 *     inertie thermique du boitier et de la carte.
 *  5. Sans extension de signe, -10 degC (raw = -160 = 0xF60 sur 12 bits) se
 *     lirait 3936 pas, soit +246 degC.
 *  6. Un axe lit environ 1000 mg (la gravite), les deux autres ~0. Sur RatBot
 *     le module est monte a l'envers : l'axe Z lit environ -1000 mg.
 *  7. Quelques dizaines a centaines de m deg/s : le biais. Le moyenner
 *     carte immobile (deux secondes) et le soustraire.
 *  8. Sans BDU, l'octet de poids fort peut appartenir a un echantillon et le
 *     faible au suivant : erreur rare mais enorme (un faux pic).
 */
