/* Correction du TP 8 (partie 1, sans OS) -- extraits de Core/Src/main.c.
 *
 * Configuration CubeMX : SPI3 Transmit Only Master, PC10 SCK, PC12 MOSI,
 * Data Size 8 bits, Prescaler 16 ; SPI123 Clock Mux = PER_CK (HSI 64 MHz,
 * bus a 4 MHz) ; PD14 SCREEN_CS (niveau de depart High), PD15 SCREEN_DC,
 * PC8 SCREEN_RST en GPIO_Output ; SYS Debug = Serial Wire.
 * Sequence d'initialisation : celle du firmware RatBot (App/drivers/ssd1309.c).
 */

/* ===== USER CODE BEGIN PV =================================================== */
static uint8_t fb[1024];

static const uint8_t init_cmds[] = {
    0xAE, 0xD5, 0x80, 0xA8, 0x3F, 0xD3, 0x00, 0x40, 0xA1, 0xC8,
    0xDA, 0x12, 0x81, 0x7F, 0xD9, 0x22, 0xDB, 0x34, 0xA4, 0xA6,
    0x20, 0x00, 0xAF,
};

static const uint8_t fenetre[] = { 0x21, 0x00, 0x7F, 0x22, 0x00, 0x07 };

static const uint8_t chiffres[10][5] = {
    { 0x3E, 0x51, 0x49, 0x45, 0x3E }, { 0x00, 0x42, 0x7F, 0x40, 0x00 },
    { 0x42, 0x61, 0x51, 0x49, 0x46 }, { 0x21, 0x41, 0x45, 0x4B, 0x31 },
    { 0x18, 0x14, 0x12, 0x7F, 0x10 }, { 0x27, 0x45, 0x45, 0x45, 0x39 },
    { 0x3C, 0x4A, 0x49, 0x49, 0x30 }, { 0x01, 0x71, 0x09, 0x05, 0x03 },
    { 0x36, 0x49, 0x49, 0x49, 0x36 }, { 0x06, 0x49, 0x49, 0x29, 0x1E },
};
/* USER CODE END PV */

/* ===== USER CODE BEGIN 0 ==================================================== */
static void send(GPIO_PinState dc, const uint8_t *buf, uint16_t n)
{
    HAL_GPIO_WritePin(SCREEN_DC_GPIO_Port, SCREEN_DC_Pin, dc);
    HAL_GPIO_WritePin(SCREEN_CS_GPIO_Port, SCREEN_CS_Pin, GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi3, (uint8_t *)buf, n, 100u);
    HAL_GPIO_WritePin(SCREEN_CS_GPIO_Port, SCREEN_CS_Pin, GPIO_PIN_SET);
}

static void send_commands(const uint8_t *cmds, uint16_t n) { send(GPIO_PIN_RESET, cmds, n); }

static void screen_init(void)
{
    HAL_GPIO_WritePin(SCREEN_RST_GPIO_Port, SCREEN_RST_Pin, GPIO_PIN_SET);
    HAL_Delay(10);
    HAL_GPIO_WritePin(SCREEN_RST_GPIO_Port, SCREEN_RST_Pin, GPIO_PIN_RESET);
    HAL_Delay(10);
    HAL_GPIO_WritePin(SCREEN_RST_GPIO_Port, SCREEN_RST_Pin, GPIO_PIN_SET);
    HAL_Delay(10);
    send_commands(init_cmds, (uint16_t)sizeof(init_cmds));
}

static void flush(void)
{
    send_commands(fenetre, (uint16_t)sizeof(fenetre));
    send(GPIO_PIN_SET, fb, (uint16_t)sizeof(fb));
}

static void fill(uint8_t v)
{
    for (uint32_t k = 0u; k < sizeof(fb); k++) { fb[k] = v; }
}

static void pixel(uint32_t x, uint32_t y, uint32_t on)
{
    if ((x >= 128u) || (y >= 64u)) { return; }
    if (on) { fb[x + (y / 8u) * 128u] |=  (uint8_t)(1u << (y % 8u)); }
    else    { fb[x + (y / 8u) * 128u] &= (uint8_t)~(1u << (y % 8u)); }
}

/* Un chiffre dans la page « page », a partir de la colonne x. */
static void digit(uint32_t x, uint32_t page, uint32_t d)
{
    for (uint32_t c = 0u; c < 5u; c++)
    {
        if ((x + c) < 128u) { fb[x + c + page * 128u] = chiffres[d % 10u][c]; }
    }
}

/* Un nombre de 0 a 99999, cadre a gauche, 6 colonnes par chiffre. */
static void number(uint32_t x, uint32_t page, uint32_t v)
{
    char     s[6];
    uint32_t n = 0u;

    do { s[n++] = (char)(v % 10u); v /= 10u; } while ((v != 0u) && (n < 5u));
    while (n > 0u) { digit(x, page, (uint32_t)s[--n]); x += 6u; }
}
/* USER CODE END 0 */

/* ===== USER CODE BEGIN 2 ====================================================
    screen_init();
   USER CODE END 2 */

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

/* Etape 3 : quatre motifs, deux secondes chacun. */
#if 0
    {
        static uint32_t m = 0u;

        switch (m)
        {
        case 0: fill(0xFFu); break;                                        /* tout allume */
        case 1: fill(0x00u); break;                                        /* tout eteint */
        case 2: for (uint32_t k = 0u; k < 1024u; k++) {                    /* verticales  */
                    fb[k] = ((k % 128u) / 8u % 2u) ? 0xFFu : 0x00u; } break;
        default: for (uint32_t k = 0u; k < 1024u; k++) {                   /* horizontales */
                    fb[k] = ((k / 128u) % 2u) ? 0xFFu : 0x00u; } break;
        }
        flush();
        m = (m + 1u) % 4u;
        HAL_Delay(2000);
    }
#endif

/* Etape 4 : cadre, diagonale et compteur. */
#if 1
    {
        static uint32_t compteur = 0u;

        fill(0x00u);
        for (uint32_t x = 0u; x < 128u; x++) { pixel(x, 0u, 1u); pixel(x, 63u, 1u); }
        for (uint32_t y = 0u; y < 64u;  y++) { pixel(0u, y, 1u); pixel(127u, y, 1u); }
        for (uint32_t x = 0u; x < 64u;  x++) { pixel(x, x, 1u); }
        number(70u, 3u, compteur);
        flush();
        compteur++;
        HAL_Delay(1000);
    }
#endif
/* USER CODE END 3 */

/* Reponses attendues aux questions :
 *  1. 0xA7 : video inversee (fond allume, dessin eteint). 0xA0 : image
 *     retournee gauche-droite (miroir).
 *  2. Horizontales de 8 points : une page sur deux a 0xFF (octets 0..127 a
 *     0xFF, 128..255 a 0x00, ...). Verticales : 8 colonnes a 0xFF, 8 a 0x00.
 *  3. 1024 octets x 8 bits / 4 MHz = 2,05 ms (plus les commandes) ; environ
 *     400 images par seconde au plus -- l'ecran n'est jamais le facteur
 *     limitant ici.
 */
