ESP32 écran, affichage d'un fond de carte

De Wiki de Mémoire Vive
Aller à la navigation Aller à la recherche

L'objectif serait de pouvoir afficher un fond de carte sur un module ESP32 écran, par exemple pour suivre des positions GPS.

Pour l'instant il ne s'agit que de la partie affichage, et qui ne fonctionne. Le test porte sur la récupération d'une tuile (un morceau de carte), c'est à dire d'un fichier d'une image en format PNG. La récupération et l'affichage se font bien. C'est la bibliothèque PNGdec qui est utilisée.

Exemple d'URL de récupération de tuile :

https://tile.openstreetmap.org/15/16614/11304.png

Voici le code, à ce stade,

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <TFT_eSPI.h>
#include <PNGdec.h>

const char* ssid = "2.4GHz-MEMOIRE-VIVE";
const char* password = "memoirevive79";
TFT_eSPI tft = TFT_eSPI();
PNG png;

// === Callback appelé par PNGdec pour chaque ligne de pixels ===
int pngDraw(PNGDRAW *pDraw) {
  static int offsetX = 0;
  static int offsetY = 0;

  if (pDraw->y == 0) {
    int width = pDraw->iWidth;
    int height = png.getHeight();
    offsetX = (tft.width() - width) / 2;
    offsetY = (tft.height() - height) / 2;

    Serial.printf("\n=== Début du rendu PNG ===\n");
    Serial.printf("Dimensions PNG : %d x %d\n", width, height);
    Serial.printf("Offset calculé : (%d, %d)\n", offsetX, offsetY);
    Serial.printf("Heap libre avant rendu : %d\n", ESP.getFreeHeap());
  }

  if (pDraw->y % 10 == 0)
    Serial.printf("Décodage ligne %d / %d\n", pDraw->y, png.getHeight());

  if (pDraw->iWidth > 512) {
    Serial.printf("⚠️ Ligne trop large (%d px)\n", pDraw->iWidth);
    return 0;
  }

  static uint16_t lineBuffer[512];
  png.getLineAsRGB565(pDraw, lineBuffer, PNG_RGB565_LITTLE_ENDIAN, 0xFFFF);

  if (pDraw->y < 3) {
    Serial.printf("Premiers pixels ligne %d : ", pDraw->y);
    for (int i = 0; i < min(4, pDraw->iWidth); i++)
      Serial.printf("%04X ", lineBuffer[i]);
    Serial.println();
  }

  tft.pushImage(offsetX, offsetY + pDraw->y, pDraw->iWidth, 1, lineBuffer);

  if (pDraw->y == png.getHeight() - 1) {
    Serial.printf("=== Fin du rendu PNG ===\n");
    Serial.printf("Heap libre après rendu : %d\n", ESP.getFreeHeap());
  }

  return 1;
}

// --- Télécharge et affiche une tuile OSM avec debug complet ---
void showTile(int zoom, int x, int y) {
  Serial.printf("Heap avant téléchargement: %d\n", ESP.getFreeHeap());

  WiFiClientSecure client;
  client.setInsecure();
  HTTPClient https;

  char url[128];
  sprintf(url, "https://tile.openstreetmap.org/%d/%d/%d.png", zoom, x, y);
  Serial.println(url);

  if (!https.begin(client, url)) {
    Serial.println("Erreur HTTPS.begin()");
    return;
  }

  https.addHeader("User-Agent", "Mozilla/5.0 (ESP32)");

  int httpCode = https.GET();
  if (httpCode != HTTP_CODE_OK) {
    Serial.printf("Erreur HTTP: %d\n", httpCode);
    Serial.printf("Réponse: %s\n", https.getString().c_str());
    https.end();
    return;
  }

  WiFiClient *stream = https.getStreamPtr();

  // --- Lecture dynamique du flux (chunked safe) ---
  std::vector<uint8_t> buf;
  unsigned long t0 = millis();
  while (https.connected()) {
    while (stream->available()) {
      buf.push_back(stream->read());
    }
    if (millis() - t0 > 10000) {
      Serial.println("⏱ Timeout lecture !");
      break;
    }
    delay(1);
  }

  int index = buf.size();
  Serial.printf("Téléchargé %d octets\n", index);

  // --- Vérification du magic number PNG ---
  if (index >= 8) {
    Serial.print("Magic number début : ");
    for (int i = 0; i < 8; i++) Serial.printf("%02X ", buf[i]);
    Serial.println();

    Serial.print("Magic number fin : ");
    for (int i = max(0, index - 8); i < index; i++) Serial.printf("%02X ", buf[i]);
    Serial.println();
  }

  // --- Vérifier IEND ---
  bool hasIEND = false;
  if (index >= 8) {
    uint8_t tail[8];
    for (int i = 0; i < 8; i++) tail[i] = buf[index - 8 + i];
    hasIEND = (tail[0] == 0x49 && tail[1] == 0x45 && tail[2] == 0x4E &&
               tail[3] == 0x44 && tail[4] == 0xAE && tail[5] == 0x42 &&
               tail[6] == 0x60 && tail[7] == 0x82);
  }
  if (!hasIEND) Serial.println("⚠️ PNG incomplet (IEND manquant)");

  // --- Calcul checksum simple ---
  uint32_t checksum = 0;
  for (uint8_t c : buf) checksum += c;
  Serial.printf("Checksum buffer: %u\n", checksum);

  // --- Décodage PNG ---
  int rc = png.openRAM(buf.data(), index, pngDraw);
  Serial.printf("Résultat openRAM = %d\n", rc);

  if (rc == PNG_SUCCESS) {
    Serial.println("✅ PNG ouvert avec succès");
    tft.startWrite();
    tft.fillScreen(TFT_BLACK);
    int decRes = png.decode(NULL, 0);
    tft.endWrite();
    Serial.printf("Résultat decode() = %d\n", decRes);
  } else {
    Serial.println("❌ Erreur PNGdec :");
    switch (rc) {
      case PNG_MEM_ERROR: Serial.println("  -> Erreur mémoire"); break;
      case PNG_INVALID_PARAMETER: Serial.println("  -> Paramètres invalides"); break;
      case PNG_INVALID_FILE: Serial.println("  -> Fichier PNG invalide ou corrompu"); break;
      case PNG_TOO_BIG: Serial.println("  -> PNG trop grand"); break;
      default: Serial.printf("  -> Code inconnu (%d)\n", rc); break;
    }
  }

  https.end();
  png.close();
  Serial.printf("Heap après libération: %d\n", ESP.getFreeHeap());
}

void setup() {
  Serial.begin(115200);
  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);

  Serial.printf("Connexion WiFi à %s...", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi connecté !");
  Serial.println(WiFi.localIP());

  tft.setTextDatum(MC_DATUM);
  tft.drawString("Chargement carte...", tft.width()/2, tft.height()/2);

  showTile(15, 16614, 11304);
}

void loop() {}

Et la sortie de la console,

Connexion WiFi à 2.4GHz-MEMOIRE-VIVE......
WiFi connecté !
192.168.1.221
Heap avant téléchargement: 183556
https://tile.openstreetmap.org/15/16614/11304.png
⏱ Timeout lecture !
Téléchargé 9638 octets
Magic number début : 89 50 4E 47 0D 0A 1A 0A 
Magic number fin : 49 45 4E 44 AE 42 60 82 
Checksum buffer: 1171860
Résultat openRAM = 0
✅ PNG ouvert avec succès

=== Début du rendu PNG ===
Dimensions PNG : 256 x 256
Offset calculé : (112, 32)
Heap libre avant rendu : 120428