..
  Copyright (C)  2023  Jeremie Salvi.
  Permission is granted to copy, distribute and/or modify this document
  under the terms of the GNU Free Documentation License, Version 1.3
  or any later version published by the Free Software Foundation;
  with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
  A copy of the license is included in the section entitled "GNU
  Free Documentation License".

Premiers tests et emulation QEMU
================================

Espressif fournit une version de QEMU modifiée pour tester du code. Cela peut avoir
plusieurs avantages :

* Commencer à coder sans attendre la livraison de notre ESP.
* Tester du code plus rapidement sans avoir à flasher notre ESP.
* Coder toute la partie web en local sur notre machine.
* Attacher un debugeur, utiliser des berakpoints, et débuger plus facilement.

Pour cela, nous reprendront le `code de la partie précédente </esp32/vscodium_integration.html#configuration-de-l-extension-c-c>`_.

Première Execution
------------------

On reprend le projet vu dans l'intégration vscodium. Pout lancer QEMU il nous faut construire la mémonire
flash pour la donner à QEMU qu'elle puisse démarrer dessus.


.. code-block:: bash

  python /opt/esp/esp-idf/components/esptool_py/esptool/esptool.py \
    --chip esp32 merge_bin --output flash_img.bin \
    --fill-flash-size 4MB --flash_mode dio --flash_size keep --flash_freq 40m \
    0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/new_project.bin

Voilà, il ne nous reste plus qu'à lancer QEMU à partir de cette image !

Emulation du système dans une machine QEMU
------------------------------------------

Il suffit maintenant de lancer notre machine QEMU à partir de la flash que l'on vient de créer :

.. code-block:: bash

  /opt/qemu/build/qemu-system-xtensa -nographic -machine esp32 \
    -drive file=flash_img.bin,if=mtd,format=raw

Et voilà, on emule la machine et on à la sortie série qui s'affiche. Pour quitter QEMU, on utilise
``Ctrl-A x``

Flasher ou monitorer en emulant un port série
---------------------------------------------

Cela ne va pas beaucoup nous servir, puisqu'il suffit de relancer qemu avec notre nouvelle
image du flash, mais il faut savoir que c'est possible en emulant les GPIO de notre ESP.

on à deux configurations : 

* ``-global driver=esp32.gpio,property=strap_mode,value=0x12`` pour monitorer la sortie.
* ``-global driver=esp32.gpio,property=strap_mode,value=0xf`` pour flasher la carte.

Attention, le port série ne peut pas recevoir deux connexions en même temps, il faut donc
couper le moniteur pour flasher et vice versa.

Monitorer QEMU
~~~~~~~~~~~~~~

On commence par lancer QEMU avec le port série en mode monitor.

.. code-block:: bash

  /opt/qemu/build/qemu-system-xtensa -nographic -machine esp32 \
    -drive file=flash_img.bin,if=mtd,format=raw \
    -global driver=esp32.gpio,property=strap_mode,value=0x12 \
    -serial tcp::5555,server,nowait

On lance ensuite le moniteur

.. code-block:: bash

  idf.py --port socket://localhost:5555 monitor

Flasher QEMU
~~~~~~~~~~~~

On commence par lancer QEMU avec le port série en mode flash.

.. code-block:: bash

  /opt/qemu/build/qemu-system-xtensa -nographic -machine esp32 \
    -drive file=flash_img.bin,if=mtd,format=raw \
    -global driver=esp32.gpio,property=strap_mode,value=0xf \
    -serial tcp::5555,server,nowait \

On flash ensuite notre machine

.. code-block:: bash

  idf.py --port socket://localhost:5555 flash

Debuger grâce de QEMU avec gdb
------------------------------

Pour attacher GDB, on lance la commande avec ``-s -S`` qui va nous ouvrir un socket tcp sur le port 1234.
pour changer de port, on utilise : ``-gdb tcp::1235``

.. code-block:: bash

  /opt/qemu/build/qemu-system-xtensa -nographic -machine esp32 \
    -drive file=flash_img.bin,if=mtd,format=raw \
    -gdb tcp:localhost:1235 -S

On peut ensuite lancer le debugeur fourni avec l'API, mettre des breakpoints, etc.

.. code-block:: bash
  :linenos:

  /root/.espressif/tools/xtensa-esp-elf-gdb/12.1_20221002/xtensa-esp-elf-gdb/bin/xtensa-esp32-elf-gdb build/main.elf

  (gdb) b app_main
  # >> Breakpoint 1 at 0x400d5170: file /root/test/sample_project/main/main.c, line 7.
  (gdb) target remote :1235
  # >> Remote debugging using :1235
  # >> 0x40000400 in ?? ()
  (gdb) c
  # Continuing.
  # Thread 1 hit Breakpoint 1, app_main () at /root/test/sample_project/main/main.c:7
  (gdb) n
  # >>  8	  int count = 0;
  (gdb) n
  # >> 11	    ESP_LOGI("FIRST TRY", "Test loop pass n° %d", count++);
  (gdb) b
  # >> Breakpoint 2 at 0x400d5175: file /root/test/sample_project/main/main.c, line 11.
  (gdb) c
  # >> Continuing.
  # >> Thread 1 hit Breakpoint 2, app_main () at /root/test/sample_project/main/main.c:11
  # >> 11	    ESP_LOGI("FIRST TRY", "Test loop pass n° %d", count++);
  (gdb) c
  # >> Continuing.
  # >> Thread 1 hit Breakpoint 2, app_main () at /root/test/sample_project/main/main.c:11
  # >> 11	    ESP_LOGI("FIRST TRY", "Test loop pass n° %d", count++);
  (gdb) print count
  # >> $1 = 2
  (gdb) set count=100
  (gdb) c
  # >> Continuing.
  # >> Thread 1 hit Breakpoint 2, app_main () at /root/test/sample_project/main/main.c:11
  # >> 11	    ESP_LOGI("FIRST TRY", "Test loop pass n° %d", count++);
  (gdb) quit

.. image:: ../images/esp32/QEMU_gdb_example.png
  :width: 400

Voilà. On va voir plus tard comment configurer cela dans vscodium


Intégration dans vscodium
-------------------------

On arrive ici à ce qui pour moi donne une vraie utilité à configurer un environnement QEMU.
On va pouvoir à partir de vscode gérer nos breakpoint, naviguer dans le code, avoir sous 
les yeux les variables et les call stack, etc.

Création des tâches
~~~~~~~~~~~~~~~~~~~

Je ne réexplique pas tout, on à déjà vu le fonctionnement dans la 
`partie précédente </esp32/vscodium_integration.html#configurer-des-taches>`_
On rajoute quelques fonctions suivantes à notre script et on ajoute les tâches pour 
lancer le débug et l'execution avec QEMU.

.. code-block:: bash
  :linenos:

  function kill_qemu {
    for i in $(ps -elf | grep 'qemu-system-xtensa' | awk '{print $4}')
    do
      echo "found process $i"
      kill $i
    done
  }

  function qemu_execute {
    kill_qemu
    python /opt/esp/esp-idf/components/esptool_py/esptool/esptool.py \
      --chip esp32 merge_bin --output flash_img.bin \
      --fill-flash-size 4MB --flash_mode dio --flash_size keep --flash_freq 40m \
      0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin \
      0x10000 build/new_project.bin
    /opt/qemu/build/qemu-system-xtensa -nographic -machine esp32 \
      -drive file=flash_img.bin,if=mtd,format=raw
    exit 0
  }

  function qemu_debug {
    kill_qemu
    python /opt/esp/esp-idf/components/esptool_py/esptool/esptool.py \
      --chip esp32 merge_bin --output flash_img.bin \
      --fill-flash-size 4MB --flash_mode dio --flash_size keep --flash_freq 40m \
      0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin \
      0x10000 build/new_project.bin
    /opt/qemu/build/qemu-system-xtensa -nographic -machine esp32 \
      -drive file=flash_img.bin,if=mtd,format=raw -s -S
    exit 0
  }

  #######################
  # Main
  #######################

  case $1 in
    kill_idf)
      echo "Killing all idf process"
      kill_idf
      ;;
    kill_qemu)
      echo "Killing all idf process"
      kill_qemu
      ;;
    qemu_execute)
      echo "Execute with QEMU"
      qemu_execute
      ;;
    qemu_debug)
      echo "Debug with QEMU"
      qemu_debug
      ;;
    *)
      echo "Missing args"
      exit 1
      ;;
  esac

.. code-block:: json
  :linenos:

  {
    "label": "Execute with QEMU",
    "type": "shell",
    "command": "${workspaceFolder}/.scripts/tasks.sh",
    "args": [
      "qemu_execute"
    ],
    "presentation": {
      "reveal": "always",
      "panel": "new",
      "close": true
    },
    "problemMatcher": []
  },
  {
    "label": "Debug with QEMU",
    "type": "shell",
    "command": "${workspaceFolder}/.scripts/tasks.sh",
    "args": [
      "qemu_debug"
    ],
    "presentation": {
      "reveal": "always",
      "panel": "new",
      "close": true
    },
    "problemMatcher": []
  },

Intégration de gdb dans vscodium
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Pour cela, il faut éditer le fichier ``.vscode/launch.json``

.. code-block:: json
  :linenos:

  {
    "configurations": [

      {
        "type": "gdb",
        "gdbpath": "/root/.espressif/tools/xtensa-esp-elf-gdb/12.1_20221002/xtensa-esp-elf-gdb/bin/xtensa-esp32-elf-gdb",
        "postDebugTask": "kill QEMU process",
        "request": "attach",
        "name": "Attach to QEMU",
        "executable": "${workspaceFolder}/build/main.elf",
        "target": ":1234",
        "remote": true,
        "cwd": "${workspaceRoot}",
        "valuesFormatting": "parseText"
      }
    ]
  }

Voilà, on n'a plus qu'à lancer la tâche ``Debug with QEMU`` et de lancer le débugeur.

.. image:: ../images/esp32/debug.png
  :width: 600

On se retrouve avec les breakpoints, les call stacks, les variables et la sortie tous affichés sans notre
environnement de travail 💪.

Prochaine étape
---------------

Les interactions avec l'électronique devant être faites avec un vrai ESP, le développement
sous QEMU ne nous sert à rien si on ne peut pas coder la partie réseau et communications depuis le PC.
Prochaine étape donc, faire tourner l'emulation avec une interface réseau pour coder notre serveur web
embarqué.