' +
+ '
How to change Python environment if you have another installed:' +
+ '
' +
+ 'python3.9 -m venv ~/.espressif/python_env/idf5.3_py3.9_env\n' +
+ 'source ~/.espressif/python_env/idf5.3_py3.9_env/bin/activate' +
+ '
' +
+ '
Check and erase if you have newer python environment versions (by default it will choose the newer one):' +
+ '
' +
+ 'rm -rf ~/.espressif/python_env/idf5.3_py3.10_en\n' +
+ ' ' +
' ' +
' ' +
' ' +
@@ -568,7 +749,24 @@
'
' +
' ' +
' ' +
- ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' Install the GDB web interface: pip3 install gdbgui ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ '
' +
+ ' ' +
+ ' ' +
+ ' ' +
' Download Driver' +
' ' +
' ' +
@@ -582,9 +780,13 @@
' ' +
' ' +
' ' +
+ ' Install ESP-IDF dependencies inside the virtual environment:' +
+ '
' +
+ ' $HOME/esp-idf-v5.3.2/install.sh' +
+ '
' +
' Load the environment variable for your board with:' +
'
' +
- ' . $HOME/esp/esp-idf/export.sh' +
+ ' . $HOME/esp-idf-v5.3.2/export.sh' +
'
' +
'
' +
' Unzip the driver.zip file and change into the driver directory associated to your board with "cd <board>", for example:' +
@@ -642,22 +844,72 @@
' ' +
' ' +
' ' +
- ' ' +
- ' ' +
- ' Flash' +
- ' Flashing...' +
- ' ' +
- ' ' +
- ' ' +
- ' ' +
- ' ' +
- ' Monitor' +
- ' Runing...' +
- ' ' +
- ' ' +
- ' ' +
- ' ' +
- ' ' +
+ // Columna 1: Flash, Clean y Erase Flash
+ '' +
+ ' ' +
+
+ ' ' +
+ ' ' +
+ ' Flash' +
+ ' Flashing...' +
+ ' ' +
+ ' ' +
+
+ ' ' +
+ ' ' +
+ ' Clean' +
+ ' Cleaning...' +
+ ' ' +
+ ' ' +
+
+ ' ' +
+ ' ' +
+ ' Erase Flash' +
+ ' Erasing...' +
+ ' ' +
+ ' ' +
+
+ ' ' +
+ ' ' +
+
+ '
' +
+ '' +
+
+ // Columna 2: Monitor, Debug y Stop
+ '' +
+ ' ' +
+
+ ' ' +
+ ' ' +
+ ' Monitor' +
+ ' Running' +
+ ' ' +
+ ' ' +
+
+ ' ' +
+ ' ' +
+ ' Debug' +
+ ' Debugging' +
+ ' ' +
+ ' ' +
+
+ ' ' +
+ ' ' +
+ ' Stop' +
+ ' Stopping' +
+ ' ' +
+ ' ' +
+
+ '
' +
+ '' +
+ ' ' +
+ '' +
' ' +
' ' +
' ' +
@@ -968,4 +1220,4 @@
return err.toString() + "\n";
}
- }
+ }
\ No newline at end of file
diff --git a/gateway/esp32-rv/.gitignore b/gateway/esp32-rv/.gitignore
deleted file mode 100644
index fbae2f16b..000000000
--- a/gateway/esp32-rv/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-sdkconfig
-sdkconfig.old
-tmp_assembly.s
-build
-main/program.s
diff --git a/gateway/esp32-rv/CMakeLists.txt b/gateway/esp32-rv/CMakeLists.txt
index 0a454d064..cc2ff9e57 100644
--- a/gateway/esp32-rv/CMakeLists.txt
+++ b/gateway/esp32-rv/CMakeLists.txt
@@ -4,3 +4,4 @@ cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(hello_world)
+target_link_libraries(${project_elf} PRIVATE "-Wl,--wrap=esp_panic_handler")
\ No newline at end of file
diff --git a/gateway/esp32-rv/README.md b/gateway/esp32-rv/README.md
index f849e2cd4..12c624737 100644
--- a/gateway/esp32-rv/README.md
+++ b/gateway/esp32-rv/README.md
@@ -1,3 +1,45 @@
-get_idf
-idf.py set-target [esp32c3]
-idf.py build
+# CREATOR ESP-32 Driver
+
+By Elisa Utrilla Arroyo
+
+## Installation and execution
+
+1. Install [Python 3.9](https://www.python.org/downloads/release/python-3913/).
+
+- In Ubuntu:
+ ```bash
+ sudo apt install software-properties-common
+ sudo add-apt-repository ppa:deadsnakes/ppa
+ sudo apt install python3.9 python3.9-venv python3.9-distutils
+ ```
+- With [uv](https://docs.astral.sh/uv):
+ ```sh
+ uv python install 3.9
+ ```
+
+3. Install the ESP-IDF framework, following [espressif's documentation](https://docs.espressif.com/projects/esp-idf/en/v5.5.1/esp32/get-started/linux-macos-setup.html)To ensure Python 3.9 is used for the installation, first create a virtual environment in `~/.espressif/python_env/idf5.3_py3.9_en`, and activate it, before executing the `install.sh` script.
+
+ ```bash
+ python3.9 -m venv ~/.espressif/python_env/idf5.3_py3.9_en
+ source ~/.espressif/python_env/idf5.3_py3.9_env/bin/activate
+
+
+ ```
+ ⚠️ If you have a newer virtual environment version for espressif, by default it will go there. Erase the virtual environments that you are not using by doing (for example):
+
+ ```
+ rm -rf ~/.espressif/python_env/idf5.3_py3.10_en
+ rm -rf ~/.espressif/python_env/idf5.3_py3.13_env
+ ```
+4. Install the requirements and move variables:
+
+ ```
+ cd ~/esp/v5.3/esp-idf
+ ./install.sh
+ . ./export.sh
+ ```
+5. Execute the gateway web service:
+
+ ```
+ python3 gateway.py
+ ```
diff --git a/gateway/esp32-rv/creator/io.h b/gateway/esp32-rv/creator/io.h
deleted file mode 100644
index 276ca38a1..000000000
--- a/gateway/esp32-rv/creator/io.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2018-2025 Felix Garcia Carballeira, Alejandro Calderon Mateos, Diego Camarmas Alonso, José Antonio Verde Jiménez
- *
- * This file is part of CREATOR.
- *
- * CREATOR is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * CREATOR is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with CREATOR. If not, see
.
- *
- */
-
-/** @file io.h
- * @brief Input Output Interface for Creator
- * @author José Antonio Verde Jiménez
- * @copyright Felix Garcia Carballeira, Alejandro Calderon Mateos, Diego Camarmas Alonso, José Antonio Verde Jiménez
- *
- * This file provides a common interface for routines for input and output.
- * The implementation is written in assembly and might change depending on the
- * device. But the interface is the same.
- */
-
-#ifndef __CREATOR_IO_HPP
-#define __CREATOR_IO_HPP
-
-/** @defgroup Creator_Input Input routines for Creator
- * @brief Input routines for Creator
- *
- * Functions get_character(), peek_character() and get_string(), use an
- * internal buffer so editing is possible. A line feed or carriage return is
- * needed to continue.
- *
- * @{
- */
-
-/** Read a character from standard input immediately. Don't show the character
- * on screen. This function doesn't work well along get_character(),
- * peek_character() or get_string(), because they need to write to a buffer to
- * work well.
- *
- * @return
- * Returns a character between 0 and 255 on success.
- * It returns -1 on error or when EOF is reached.
- */
-int get_immediate ();
-
-/** Read a character from standard input. It echos the character.
- *
- * @return
- * Returns a character between 0 and 255 on success.
- * It returns -1 on error or when EOF is reached.
- */
-int get_character ();
-
-/** Peek on the next character on the standard input, but don't read it. That
- * way you can see the next character without "destroying it".
- *
- * @return
- * Returns a character between 0 and 255 on success.
- * It returns -1 on error or when EOF is reached.
- */
-int peek_character ();
-
-/** Read from standard input into a string buffer. The last character is
- * written to be '\0'.
- *
- * This function supposes that the length of the string is *at least*,
- * length + 1 characters long. string[length] will be 0.
- *
- * Note that carriage returns, line feeds and carriage return + line feed are
- * all treated like line feeds.
- *
- * @param[out] string
- * A pointer to the begining of the string buffer.
- *
- * @param[in] length
- * The amount of characters to be read from standard input.
- */
-void get_string (char *string, int length);
-
-/** @} */
-
-/** @defgroup Creator_Output Output routines for Creator
- * @brief Output routines for Creator
- *
- * @{
- */
-
-
-/** Write a character immediately (flush and synchronise it) on standard output
- * and display it on the screen.
- *
- * @param[in] c
- * A character.
- */
-void put_immediate (char c);
-
-/** Write a character zero-terminated string on standard output, flush and
- * synchronise standard output and display it on the screen.
- *
- * @param[in] string
- * The pointer to the begining of the string.
- */
-void put_zstring (char *string);
-
-/** Write a string with a given length on standard output, flush and
- * synchronise standard output and display it on the screen.
- *
- * @param[in] string
- * The pointer to the begining of the string.
- *
- * @param[in] length
- * The length of said string
- */
-void put_string (char *string, int length);
-
-/** @} */
-
-#endif//__CREATOR_IO_HPP
diff --git a/gateway/esp32-rv/gateway.py b/gateway/esp32-rv/gateway.py
index f09d5ee64..0c21f69e7 100755
--- a/gateway/esp32-rv/gateway.py
+++ b/gateway/esp32-rv/gateway.py
@@ -2,7 +2,7 @@
#
-# Copyright 2022-2024 Felix Garcia Carballeira, Diego Carmarmas Alonso, Alejandro Calderon Mateos
+# Copyright 2022-2024 Felix Garcia Carballeira, Diego Carmarmas Alonso, Alejandro Calderon Mateos, Elisa Utrilla Arroyo
#
# This file is part of CREATOR.
#
@@ -21,10 +21,71 @@
#
+import glob
+import sys
+import threading
+from time import sleep, time
from flask import Flask, request, jsonify, send_file, Response
from flask_cors import CORS, cross_origin
import subprocess, os, signal
+import logging
+# Configure logging
+logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
+
+BUILD_PATH = '.'
+process_holder = {}
+
+#### (*) Cleaning functions
+def do_fullclean_request(request):
+ """ Full clean the build directory """
+ try:
+ req_data = request.get_json()
+ target_device = req_data['target_port']
+ req_data['status'] = ''
+ error = 0
+ # flashing steps...
+ if error == 0:
+ do_cmd_output(req_data, ['idf.py','-C', BUILD_PATH,'fullclean'])
+ if error == 0:
+ req_data['status'] += 'Full clean done.\n'
+ except Exception as e:
+ req_data['status'] += str(e) + '\n'
+ return jsonify(req_data)
+
+def do_eraseflash_request(request):
+ """ Erase flash the target device """
+ try:
+ req_data = request.get_json()
+ target_device = req_data['target_port']
+ req_data['status'] = ''
+ # flashing steps...
+ error = 0
+ if error == 0:
+ error = do_cmd_output(req_data, ['idf.py','-C', BUILD_PATH,'-p',target_device,'erase-flash'])
+ if error == 0:
+ req_data['status'] += 'Erase flash done. Please, unplug and plug the cable(s) again\n'
+
+ except Exception as e:
+ req_data['status'] += str(e) + '\n'
+
+ return jsonify(req_data)
+
+def do_stop_monitor_request(request):
+ """Shortcut for stopping Monitor / debug """
+ try:
+ req_data = request.get_json()
+ req_data['status'] = ''
+ print("Killing Monitor")
+ error = kill_all_processes("idf.py")
+ if error == 0:
+ req_data['status'] += 'Process stopped\n'
+
+
+ except Exception as e:
+ req_data['status'] += str(e) + '\n'
+
+ return jsonify(req_data)
# (1) Get form values
def do_get_form(request):
@@ -56,7 +117,6 @@ def creator_build(file_in, file_out):
fout.write("addi sp, sp, -8\n")
fout.write("sw ra, 4(sp)\n")
fout.write("sw a0, 0(sp)\n")
-
fout.write("jal ra, _rdcycle\n")
fout.write("mv "+ data[1] +", a0\n")
@@ -67,60 +127,6 @@ def creator_build(file_in, file_out):
fout.write("####################\n")
continue
- if (data[0] == 'ecall'):
- fout.write("#### ecall ####\n")
- fout.write("addi sp, sp, -128\n")
- fout.write("sw x1, 120(sp)\n")
- fout.write("sw x3, 112(sp)\n")
- fout.write("sw x4, 108(sp)\n")
- fout.write("sw x5, 104(sp)\n")
- fout.write("sw x6, 100(sp)\n")
- fout.write("sw x7, 96(sp)\n")
- fout.write("sw x8, 92(sp)\n")
- fout.write("sw x9, 88(sp)\n")
- fout.write("sw x18, 52(sp)\n")
- fout.write("sw x19, 48(sp)\n")
- fout.write("sw x20, 44(sp)\n")
- fout.write("sw x21, 40(sp)\n")
- fout.write("sw x22, 36(sp)\n")
- fout.write("sw x23, 32(sp)\n")
- fout.write("sw x24, 28(sp)\n")
- fout.write("sw x25, 24(sp)\n")
- fout.write("sw x26, 20(sp)\n")
- fout.write("sw x27, 16(sp)\n")
- fout.write("sw x28, 12(sp)\n")
- fout.write("sw x29, 8(sp)\n")
- fout.write("sw x30, 4(sp)\n")
- fout.write("sw x31, 0(sp)\n")
-
- fout.write("jal _myecall\n")
-
- fout.write("lw x1, 120(sp)\n")
- fout.write("lw x3, 112(sp)\n")
- fout.write("lw x4, 108(sp)\n")
- fout.write("lw x5, 104(sp)\n")
- fout.write("lw x6, 100(sp)\n")
- fout.write("lw x7, 96(sp)\n")
- fout.write("lw x8, 92(sp)\n")
- fout.write("lw x9, 88(sp)\n")
- fout.write("lw x18, 52(sp)\n")
- fout.write("lw x19, 48(sp)\n")
- fout.write("lw x20, 44(sp)\n")
- fout.write("lw x21, 40(sp)\n")
- fout.write("lw x22, 36(sp)\n")
- fout.write("lw x23, 32(sp)\n")
- fout.write("lw x24, 28(sp)\n")
- fout.write("lw x25, 24(sp)\n")
- fout.write("lw x26, 20(sp)\n")
- fout.write("lw x27, 16(sp)\n")
- fout.write("lw x28, 12(sp)\n")
- fout.write("lw x29, 8(sp)\n")
- fout.write("lw x30, 4(sp)\n")
- fout.write("lw x31, 0(sp)\n")
- fout.write("addi sp, sp, 128\n")
- fout.write("###############\n")
- continue
-
fout.write(line)
# close input + output files
@@ -174,14 +180,79 @@ def do_flash_request(request):
ret = text_file.write(asm_code)
text_file.close()
+ # Kill debug processes
+ if 'openocd' in process_holder:
+ logging.debug('Killing OpenOCD')
+ kill_all_processes("openocd")
+ process_holder.pop('openocd', None)
+
+ if 'gdbgui' in process_holder:
+ logging.debug('Killing GDBGUI')
+ kill_all_processes("gdbgui")
+ process_holder.pop('gdbgui', None)
+
# transform th temporal assembly file
error = creator_build('tmp_assembly.s', "main/program.s");
if error != 0:
req_data['status'] += 'Error adapting assembly file...\n'
# flashing steps...
+ if error == 0 :
+ error = check_uart_connection()
+ if error != 0:
+ req_data['status'] += 'No UART port found.\n'
+ logging.error("No UART port found.")
+ raise Exception("No UART port found")
if error == 0:
error = do_cmd(req_data, ['idf.py', 'fullclean'])
+ # Disable memory protection
+ sdkconfig_path = os.path.join(BUILD_PATH, "sdkconfig")
+ # 1. Check out previous sdkconfig
+ # (*) This configuration is EXCUSIVELY FOR ESP-IDF WITHOUT ARDUINO
+ defaults_path = os.path.join(BUILD_PATH, "sdkconfig.defaults")
+ if target_board == 'esp32c3':
+ with open(defaults_path, "w") as f:
+ f.write(
+ "# CONFIG_ESP_SYSTEM_MEMPROT_FEATURE is not set\n"
+ "# CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_LOCK is not set\n"
+ )
+ #TODO: Add other boards here...
+ elif target_board == 'esp32c6':
+ with open(defaults_path, "w") as f:
+ f.write(
+ "CONFIG_FREERTOS_HZ=1000\n"
+ "# CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT is not set\n"
+ )
+
+ # 2. If previous sdkconfig exists, check if mem protection is disabled (for debug purposes)
+ if os.path.exists(sdkconfig_path):
+ if target_board == 'esp32c3':
+ # Memory Protection
+ do_cmd(req_data, [
+ 'sed', '-i',
+ r'/^CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=/c\# CONFIG_ESP_SYSTEM_MEMPROT_FEATURE is not set',
+ sdkconfig_path
+ ])
+ # Memory protection lock
+ do_cmd(req_data, [
+ 'sed', '-i',
+ r'/^CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_LOCK=/c\# CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_LOCK is not set',
+ sdkconfig_path
+ ])
+ elif target_board == 'esp32c6':
+ #CONFIG_FREERTOS_HZ=1000
+ do_cmd(req_data, [
+ 'sed', '-i',
+ r'/^CONFIG_FREERTOS_HZ=/c\CONFIG_FREERTOS_HZ=1000',
+ sdkconfig_path
+ ])
+ # PMP IDRAM split
+ do_cmd(req_data, [
+ 'sed', '-i',
+ r'/^CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT=/c\# CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT is not set',
+ sdkconfig_path
+ ])
+ #TODO: Add other boards here...
if error == 0:
error = do_cmd(req_data, ['idf.py', 'set-target', target_board])
if error == 0:
@@ -202,8 +273,28 @@ def do_monitor_request(request):
target_device = req_data['target_port']
req_data['status'] = ''
- do_cmd(req_data, ['idf.py', '-p', target_device, 'monitor'])
-
+ # Kill debug process
+
+ if 'openocd' in process_holder:
+ logging.debug('Killing OpenOCD')
+ kill_all_processes("openocd")
+ process_holder.pop('openocd', None)
+
+ if 'gdbgui' in process_holder:
+ logging.debug('Killing GDBGUI')
+ kill_all_processes("gdbgui")
+ process_holder.pop('gdbgui', None)
+
+ build_root = BUILD_PATH +'/build'
+ if check_uart_connection() != 0:
+ req_data['status'] += "No UART port found\n"
+ return jsonify(req_data)
+ if os.path.isdir(build_root) and os.listdir(build_root):
+ do_cmd(req_data, ['idf.py', '-p', target_device, 'monitor'])
+ else:
+ req_data['status'] += "No ELF file found in build directory.\n"
+ logging.error("No elf found.")
+
except Exception as e:
req_data['status'] += str(e) + '\n'
@@ -261,6 +352,251 @@ def do_stop_flash_request(request):
return jsonify(req_data)
+# (6) Debug
+
+# (6.1) Physical connections check
+def check_uart_connection():
+ """ Checks UART devices """
+ devices = glob.glob('/dev/ttyUSB*')
+ logging.debug(f"Found devices: {devices}")
+ if "/dev/ttyUSB0" in devices:
+ logging.info("Found UART.")
+ return 0
+ elif devices:
+ logging.error("Other UART devices found (Is the name OK?).")
+ return 0
+ else:
+ logging.error("NO UART port found.")
+ return 1
+
+def check_jtag_connection():
+ """ Checks JTAG devices """
+ command = ["lsusb"]
+ try:
+ lsof = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ output, errs = lsof.communicate(timeout=5)
+ if output:
+ output_text = output.decode(errors="ignore")
+ if "JTAG" in output_text:
+ logging.info("JTAG found")
+ return True
+ else:
+ logging.warning("JTAG missing")
+ return False
+ except subprocess.TimeoutExpired:
+ lsof.kill()
+ output, errs = lsof.communicate()
+ except Exception as e:
+ logging.error(f"Error checking JTAG: {e}")
+ return None
+ return False
+# --- (6.2) Debug processes monitoring functions ---
+
+def check_gdb_connection():
+ """ Checks gdb status """
+ command = ["lsof", "-i", ":3333"]
+ try:
+ lsof = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ output, errs = lsof.communicate(timeout=5)
+ logging.debug("GDB connection output: %s", output.decode())
+ return output.decode()
+ except subprocess.TimeoutExpired:
+ lsof.kill()
+ output, errs = lsof.communicate()
+ logging.error(" GDB:Timeout waiting for GDB connection.")
+ except Exception as e:
+ logging.error(f"Error checking GDB: {e}")
+ return None
+ return False
+
+def monitor_openocd_output(req_data, cmd_args, name):
+ logfile_path = os.path.join(BUILD_PATH, f"{name}.log")
+ try:
+ with open(logfile_path, "a", encoding="utf-8") as logfile:
+ process_holder[name] = subprocess.Popen(
+ cmd_args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ bufsize=1,
+ universal_newlines=True
+ )
+ proc = process_holder[name]
+
+ # Logfile
+ for line in proc.stdout:
+ line = line.rstrip()
+ logfile.write(line + "\n")
+ logfile.flush()
+ logging.debug(f"[{name}] {line}")
+
+ proc.stdout.close()
+ retcode = proc.wait()
+ logging.debug(f"Process {name} finished with code {retcode}")
+ return proc
+
+ except Exception as e:
+ logging.error(f"Error executing command {name}: {e}")
+ process_holder.pop(name, None)
+ return None
+
+def kill_all_processes(process_name):
+ try:
+ if not process_name:
+ logging.error("El nombre del proceso no puede estar vacío.")
+ return 1
+
+ # Comando para obtener los PIDs de los procesos
+ get_pids_cmd = f"ps aux | grep '[{process_name[0]}]{process_name[1:]}' | awk '{{print $2}}'"
+ result = subprocess.run(get_pids_cmd, shell=True, capture_output=True, text=True)
+
+ # PIDs list
+ pids = result.stdout.strip().split()
+
+ if not pids:
+ logging.warning(f"Not processes found '{process_name}'.")
+ return 1 # Devuelve 1 para indicar que no se hizo nada
+
+ # Ejecuta kill solo si hay PIDs
+ kill_cmd = f"kill -9 {' '.join(pids)}"
+ result = subprocess.run(kill_cmd, shell=True, capture_output=True, timeout=120, check=False)
+
+ if result.returncode != 0:
+ logging.error(f"Error al intentar matar los procesos {process_name}. Salida: {result.stderr.strip()}")
+ else:
+ logging.debug(f"Todos los procesos '{process_name}' han sido eliminados.")
+
+ return result.returncode
+
+ except subprocess.TimeoutExpired as e:
+ logging.error(f"El proceso excedió el tiempo de espera: {e}")
+ return 1
+
+ except subprocess.CalledProcessError as e:
+ logging.error(f"Error al ejecutar el comando: {e}")
+ return 1
+
+ except Exception as e:
+ logging.error(f"Ocurrió un error inesperado: {e}")
+ return 1
+
+
+# (6.3) OpenOCD Function
+def start_openocd_thread(req_data):
+ target_board = req_data['target_board']
+ script_board = './openocd_scripts/openscript_' + target_board + '.cfg'
+ logging.debug(f"OpenOCD script: {script_board}")
+ try:
+ thread = threading.Thread(
+ target=monitor_openocd_output,
+ args=(req_data, ['openocd', '-f', script_board], 'openocd'),
+ daemon=True
+ )
+ thread.start()
+ logging.debug("Starting OpenOCD thread...")
+ return thread
+ except Exception as e:
+ req_data['status'] += f"Error starting OpenOCD: {str(e)}\n"
+ logging.error(f"Error starting OpenOCD: {str(e)}")
+ return None
+# (6.4) GDBGUI function
+def start_gdbgui(req_data):
+ route = os.path.join(BUILD_PATH, 'gdbinit')
+ logging.debug(f"GDB route: {route}")
+ route = os.path.join(BUILD_PATH, 'gdbinit')
+ if os.path.exists(route) and os.path.exists("./gbdscript.gdb"):
+ logging.debug(f"GDB route: {route} exists.")
+ else:
+ logging.error(f"GDB route: {route} does not exist.")
+ req_data['status'] += f"GDB route: {route} does not exist.\n"
+ return jsonify(req_data)
+ req_data['status'] = ''
+ if check_uart_connection():
+ req_data['status'] += f"No UART found\n"
+ return jsonify(req_data)
+
+ logging.info("Starting GDBGUI...")
+ gdbgui_cmd = ['idf.py', '-C', BUILD_PATH, 'gdbgui', '--gdbinit', route, 'monitor']
+ sleep(5)
+ try:
+ process_holder['gdbgui'] = subprocess.run(
+ gdbgui_cmd,
+ stdout=sys.stdout,
+ stderr=sys.stderr,
+ text=True
+ )
+ if process_holder['gdbgui'].returncode != -9 and process_holder['gdbgui'].returncode != 0:
+ logging.error(f"Command failed with return code {process_holder['gdbgui'].returncode}")
+
+ except subprocess.CalledProcessError as e:
+ logging.error("Failed to start GDBGUI: %s", e)
+ req_data['status'] += f"Error starting GDBGUI (code {e.returncode}): {e.stderr}\n"
+ return None
+ except Exception as e:
+ logging.error("Unexpected error in GDBGUI: %s", e)
+ req_data['status'] += f"Unexpected error starting GDBGUI: {e}\n"
+ return None
+
+ req_data['status'] += f"Finished debug session: {e}\n"
+ return jsonify(req_data)
+
+
+
+def do_debug_request(request):
+ global stop_event
+ global process_holder
+ error = 0
+ try:
+ req_data = request.get_json()
+ target_device = req_data['target_port']
+ req_data['status'] = ''
+
+ # Check .elf files in BUILD_PATH
+ route = BUILD_PATH +'/build'
+ logging.debug(f"Checking for ELF files in {route}")
+ elf_files = [f for f in os.listdir(route) if f.endswith(".elf")]
+ if not elf_files:
+ req_data['status'] += "No ELF file found in build directory.\n"
+ logging.error("No ELF file found in build directory.")
+ return jsonify(req_data)
+ logging.debug("Delete previous work")
+ # Clean previous debug system
+ if error == 0:
+ if 'openocd' in process_holder:
+ logging.debug('Killing OpenOCD')
+ kill_all_processes("openocd")
+ process_holder.pop('openocd', None)
+ # Check UART
+ if check_uart_connection():
+ req_data['status'] += f"No UART found\n"
+ return jsonify(req_data)
+ # Check if JTAG is connected
+ if not check_jtag_connection():
+ req_data['status'] += "No JTAG found\n"
+ return jsonify(req_data)
+
+ # Start OpenOCD
+ logging.info("Starting OpenOCD...")
+ openocd_thread = start_openocd_thread(req_data)
+ while process_holder.get('openocd') is None:
+ sleep(1)
+ #start_openocd_thread(req_data)
+
+ # Start gdbgui
+ #logging.info("Starting gdbgui")
+ error = start_gdbgui(req_data)
+ if error != 0:
+ req_data['status'] += "Error starting gdbgui\n"
+ return jsonify(req_data)
+ else:
+ req_data['status'] += "Build error\n"
+
+ except Exception as e:
+ req_data['status'] += f"Unexpected error: {str(e)}\n"
+ logging.error(f"Exception in do_debug_request: {e}")
+
+ return jsonify(req_data)
+
# Setup flask and cors:
app = Flask(__name__)
@@ -302,6 +638,30 @@ def post_job():
def post_stop_flash():
return do_stop_flash_request(request)
+# (6) POST /fullclean -> clean build directory
+@app.route("/fullclean", methods=["POST"])
+@cross_origin()
+def post_fullclean_flash():
+ return do_fullclean_request(request)
+
+# (7) POST /eraseflash -> clean board flash
+@app.route("/eraseflash", methods=["POST"])
+@cross_origin()
+def post_erase_flash():
+ return do_eraseflash_request(request)
+
+# (8) POST /debug -> debug
+@app.route("/debug", methods=["POST"])
+@cross_origin()
+def post_debug():
+ return do_debug_request(request)
+
+# (9) Stop monitor
+@app.route("/stopmonitor", methods=["POST"])
+@cross_origin()
+def post_stop_monitor():
+ return do_stop_monitor_request(request)
+
# Run
app.run(host='0.0.0.0', port=8080, use_reloader=False, debug=True)
\ No newline at end of file
diff --git a/gateway/esp32-rv/gbdscript.gdb b/gateway/esp32-rv/gbdscript.gdb
new file mode 100644
index 000000000..263322e31
--- /dev/null
+++ b/gateway/esp32-rv/gbdscript.gdb
@@ -0,0 +1,16 @@
+delete breakpoints
+target extended-remote :3333
+set remotetimeout 10
+monitor reset halt
+maintenance flush register-cache
+b main
+continue
+
+define hook-stop
+ set $inst = *(unsigned int *)$pc
+ if $inst == 0x00000073
+ set $next = $pc + 4
+ tbreak *$next
+ continue
+ end
+end
diff --git a/gateway/esp32-rv/gdbinit b/gateway/esp32-rv/gdbinit
new file mode 100644
index 000000000..77a153b98
--- /dev/null
+++ b/gateway/esp32-rv/gdbinit
@@ -0,0 +1,2 @@
+source ./build/gdbinit/symbols
+source ./gbdscript.gdb
diff --git a/gateway/esp32-rv/main/CMakeLists.txt b/gateway/esp32-rv/main/CMakeLists.txt
index 37526735f..defd3a360 100644
--- a/gateway/esp32-rv/main/CMakeLists.txt
+++ b/gateway/esp32-rv/main/CMakeLists.txt
@@ -1,9 +1,9 @@
idf_component_register(
SRCS
+ "syscall/test_panic.c"
+ "syscall/return_from_panic.S"
"program.s"
"creator-esp.c"
- "ecall.s"
- "io.s"
"creator.s"
INCLUDE_DIRS
"..")
diff --git a/gateway/esp32-rv/main/creator-esp.c b/gateway/esp32-rv/main/creator-esp.c
index a2ebb5a31..332bd8b71 100644
--- a/gateway/esp32-rv/main/creator-esp.c
+++ b/gateway/esp32-rv/main/creator-esp.c
@@ -19,7 +19,7 @@
//////////////////////// para leer del monitor
#include "esp_system.h"
#include "esp_console.h"
-#include "esp_vfs_dev.h"
+#include "driver/uart_vfs.h"
#include "esp_vfs_fat.h"
////////////////////////
@@ -47,9 +47,9 @@ void app_main(void)
{
/////////// para leer del monitor
ESP_ERROR_CHECK(uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0));
- esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
- esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR);
- esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF);
+ uart_vfs_dev_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
+ uart_vfs_dev_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR);
+ uart_vfs_dev_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF);
/////////
printf("Started program... \n");
diff --git a/gateway/esp32-rv/main/creator.s b/gateway/esp32-rv/main/creator.s
index 43069045d..4af8fd554 100644
--- a/gateway/esp32-rv/main/creator.s
+++ b/gateway/esp32-rv/main/creator.s
@@ -1,5 +1,5 @@
#
-# Copyright 2018-2025 Felix Garcia Carballeira, Alejandro Calderon Mateos, Diego Camarmas Alonso, José Antonio Verde Jiménez
+# Copyright 2018-2024 Felix Garcia Carballeira, Alejandro Calderon Mateos, Diego Camarmas Alonso, José Antonio Verde Jiménez
#
# This file is part of CREATOR.
#
diff --git a/gateway/esp32-rv/main/ecall.s b/gateway/esp32-rv/main/ecall.s
deleted file mode 100644
index 98eba8907..000000000
--- a/gateway/esp32-rv/main/ecall.s
+++ /dev/null
@@ -1,345 +0,0 @@
-#
-# Copyright 2018-2025 Felix Garcia Carballeira, Alejandro Calderon Mateos, Diego Camarmas Alonso, José Antonio Verde Jiménez
-#
-# This file is part of CREATOR.
-#
-# CREATOR is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# CREATOR is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with CREATOR. If not, see
.
-#
-
-# ecall Module
-# ============
-# This module implements the _myecall function, which will be used in a future
-# to implement the ecall instruction. For the time being, every instance of
-# ecall is replaced with a call to _myecall (pushing all the registers first,
-# so they can be restored after the call).
-#
-# AUTHOR: José Antonio Verde Jiménez
-
-# ==== .rodata ============================================================== #
-.section .rodata
-
-.align 2
-
-vector:
- .word unknown # a7 = 0
- .word print_int # a7 = 1
- .word print_float # a7 = 2
- .word print_double # a7 = 3
- .word print_string # a7 = 4
- .word read_int # a7 = 5
- .word read_float # a7 = 6
- .word read_double # a7 = 7
- .word read_string # a7 = 8
- .word sbrk # a7 = 9
- .word exit # a7 = 10
- .word print_char # a7 = 11
- .word read_char # a7 = 12
-
-vector_size:
- .word (vector_size - vector) / 4
-
-unknown_msg:
- .asciz "\033[31;1m¡Unknown system call!\033[0m\n"
-
-not_implemented_msg:
- .asciz "\033[31;1mNot implemented\033[0m\n"
-
-sbrk_error_msg:
- .asciz "\033[31;1mSBRK: Memory exhausted\033[0m\n"
-
-integers:
- .byte -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
- .byte -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
- .byte -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
- .byte 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1
- .byte -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1
- .byte -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
- .byte -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1
- .byte -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
-
-images: .byte '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
-
-# ==== .data ================================================================ #
-.section .data
-
-.set POOL_CAPACITY, 65536
-
-.align 2
-pool_capacity: .word POOL_CAPACITY
-pool_size: .word 0
-
-pool: .space POOL_CAPACITY
-
-# A small buffer for strings
-buffer: .space 256
-buffer_end:
-
-# ==== .text ================================================================ #
-.section .text
-
-.type _ecall, @function
-.globl _myecall
-
-_not_implemented:
- addi sp, sp, -4
- sw ra, 0(sp)
- la a0, not_implemented_msg
- li a7, 4
- jal ra, _myecall
- lw ra, 0(sp)
- addi sp, sp, 4
- jr ra
-
-unknown:
- addi sp, sp, -4
- sw ra, 0(sp)
- li a7, 4
- la a0, unknown_msg
- jal ra, _myecall
- lw ra, 0(sp)
- addi sp, sp, 4
- jr ra
-
-# FUNCTION: void print_int (int number, int base = 10)
-# PARAMETERS: int a0 : The number base, it is ignored, 10 is always used.
-# RETURNS: NONE
-# DESCRIPTION: Print an integer into the string using the given base.
-
-print_int:
- addi sp, sp, -4
- sw ra, 0(sp)
-
- # a0 : number
- # a1 : base
- li a1, 10
- la a2, buffer_end
- la a3, images
-
- sgtz t0, a0 # t0 := a0 > 0 ? 1 : 0
- seqz t1, a0 # t1 := a0 == 0 ? 1 : 0
- or t0, t0, t1 # t0 := t0 or t1
- slli t0, t0, 1 # t0 := 2 * t0
- addi t4, t0, -1 # t4 := t0 - 1
- # Now, t4 is -1 if negative and 1 if positive or zero
- sltz a4, a0 # a4 := a0 < 0 ? 1 : 0
-
- # End the string with a zero
- sb zero, -1(a2)
- addi a2, a2, -2
-
- print_int_loop:
- rem t0, a0, a1 # value := number rem base
- mul t0, t0, t4 # Negative number case
- div a0, a0, a1 # number := number / base
- add t0, a3, t0 # images + value
- lb t0, 0(t0) # *(images + value)
- sb t0, 0(a2) # *buffer = *(images + value)
- addi a2, a2, -1
- bne a0, zero, print_int_loop
-
- beq a4, zero, print_int_positive
- print_int_negative:
- li t0, '-'
- sb t0, 0(a2)
- addi a2, a2, -1
-
- print_int_positive:
- addi a0, a2, 1
-
- jal ra, put_zstring
-
- lw ra, 0(sp)
- addi sp, sp, 4
- jr ra
-
-print_float:
- j _not_implemented # TODO
-print_double:
- j _not_implemented # TODO
-
-print_string:
- j put_zstring
-
-# FUNCTION: (int, bool) read_int (int base = 10)
-# PARAMETERS: int a0 : The number base, it is ignored, 10 is always used.
-# RETURNS: int a0 : The result of reading the integer
-# bool a1 : true if it succeeded, false if it failed
-# DESCRIPTION: Read an integer from standard input and return it. It stops
-# reading if it finds a non integer value.
-read_int:
- addi sp, sp, -20
- sw ra, 0(sp)
- sw s0, 4(sp) # For the result
- sw s1, 8(sp) # For the base
- sw s2, 12(sp) # For the sign
- sw s3, 16(sp) # Characters read
-
- jal ra, skip_separators
-
- mv s0, zero # Result = 0
- li a0, 10 # s0 will contain the base, in a future this parameter will
- mv s1, a0 # be accepted.
- li s2, 1 # Positive
- mv s3, zero
-
- li t0, 2
- li t1, 16
- blt s1, t0, read_int_bad_base # a1 < 2 (Invalid base)
- bgt s1, t1, read_int_bad_base # a1 > 16 (Invalid base)
-
- jal ra, peek_character
- li t0, '+'
- li t1, '-'
- beq a0, t0, read_int_positive
- beq a0, t1, read_int_negative
- j read_int_parse
- read_int_negative:
- li s2, -1
- read_int_positive:
- jal ra, get_character # Feed a character and ignore it.
- read_int_parse:
- jal ra, peek_character
- blt a0, zero, read_int_stop # exit when char < 0
- la t0, integers
- add t0, t0, a0
- lb t0, 0(t0) # t0 = integers[char]
- blt t0, zero, read_int_stop # exit when t0 < -1
- bge t0, s1, read_int_stop # exit when not in base
- addi s3, s3, 1
- mul s0, s0, s1
- add s0, s0, t0 # result = result * base + integers[char]
- jal ra, get_character # read it
- j read_int_parse
-
- read_int_stop:
- beq s3, zero, read_int_failed # No characters read.
- mul a0, s0, s2
- li a1, 1 # return (result * sign, true)
- j read_int_end
-
- read_int_failed:
- read_int_bad_base:
- mv a0, zero
- mv a1, zero
- j read_int_end
-
- read_int_end:
- lw ra, 0(sp)
- lw s0, 4(sp)
- lw s1, 8(sp)
- lw s2, 12(sp)
- lw s3, 16(sp)
- addi sp, sp, 20
- jr ra
-
-read_float:
- j _not_implemented # TODO
-read_double:
- j _not_implemented # TODO
-read_string:
- j get_string
-
-# TODO: Implement a good memory pool
-sbrk:
- addi sp, sp, -4
- sw ra, 0(sp)
-
- la t0, pool_capacity
- la t1, pool_size
- la t2, pool
-
- lw t3, 0(t0) # capacity
- lw t4, 0(t1) # size
- add t5, t4, a0 # t5 = size + a0
- bgt t5, t3, sbrk_overflow
-
- sbrk_valid:
- sw t5, 0(t1) # size = size'old + a0
- add a0, t2, t4 # return pool + size'old
- j sbrk_end
-
- sbrk_overflow:
- la a0, sbrk_error_msg
- la a7, 4
- jal ra, _myecall
-
- sbrk_end:
- lw ra, 0(sp)
- addi sp, sp, 4
- jr ra
-
-exit:
- j _exit
-
-print_char:
- j put_immediate
-
-read_char:
- j get_character
-
-_myecall:
- addi sp, sp, -4
- sw ra, 0(sp)
-
- # Check it is in range
- la t0, vector_size
- lw t0, 0(t0)
- blt a7, zero, _myecall_unknown
- bgt a7, t0, _myecall_unknown
-
- # # Call it
- la t0, vector
- slli a7, a7, 2
- add t0, t0, a7
- lw t0, 0(t0)
- jalr ra, t0 # goto vector[a7 * 4]
- j _myecall_end
-
- _myecall_unknown:
- la a0, unknown_msg
- li a7, 4
- jal ra, _myecall # print_string
-
- _myecall_end:
- lw ra, 0(sp)
- addi sp, sp, 4
- jr ra
-
-# FUNCTION: skip_separators
-# PARAMETERS: NONE
-# RETURNS: NONE
-# DESCRIPTION: This function skips separators (spaces, tabulations...), until
-# it finds something different.
- .type skip_separators, @function
-skip_separators:
- addi sp, sp, -4
- sw ra, 0(sp)
- skip_separators_loop:
- jal ra, peek_character
- li t0, '\n' # Line feed
- li t1, '\r' # Carriage return
- li t2, ' ' # Space
- li t3, '\t' # Tabulator
- beq a0, t0, skip_separators_skip_it
- beq a0, t1, skip_separators_skip_it
- beq a0, t2, skip_separators_skip_it
- beq a0, t3, skip_separators_skip_it
- j skip_separators_end
- skip_separators_skip_it:
- jal ra, get_character
- j skip_separators_loop
- skip_separators_end:
- lw ra, 0(sp)
- addi sp, sp, 4
- jr ra
diff --git a/gateway/esp32-rv/main/io.s b/gateway/esp32-rv/main/io.s
deleted file mode 100644
index ce6c46e85..000000000
--- a/gateway/esp32-rv/main/io.s
+++ /dev/null
@@ -1,571 +0,0 @@
-#
-# Copyright 2018-2025 Felix Garcia Carballeira, Alejandro Calderon Mateos, Diego Camarmas Alonso, José Antonio Verde Jiménez
-#
-# This file is part of CREATOR.
-#
-# CREATOR is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# CREATOR is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with CREATOR. If not, see
.
-#
-
-# I/O Module
-# ==========
-# The following constraints hold for the device's standard I/O:
-#
-# * Reading a character doesn't echo.
-# * Once a character is written you cannot delete it (backspace) or move
-# back (arrow keys).
-# * Writing doesn't echo until a line feed is issued.
-#
-# Therefore this module attempts to solve this by creating a very simple
-# editable line where input can be modified using arrow keys, and characters
-# can be removed with backspace.
-#
-# This file implements the following global functions:
-#
-# int get_immediate ()
-# int get_character ()
-# int peek_character ()
-# void get_string (char *string, int length);
-#
-# void put_immediate (char c)
-# void put_zstring (char *c);
-# void put_string (char *c, int length);
-#
-# TODO: Add latin-1 for accents
-#
-# AUTHOR: José Antonio Verde Jiménez
-
-# ==== .rodata ============================================================== #
-.section .rodata
-
-go_right_str: .asciz "\033[1C"
-go_left_str: .asciz "\033[1D"
-
-# ==== .data ================================================================ #
-
-.section .data
-
-# char line[]
-# A very long string buffer (UTF-8) where the input characters are stored and
-# modified. Writing is done to this string until a newline character is found
-# (\n, \r or \r\n), then I/O operations can continue.
-.set LINE_SIZE, 80
-.align 2
-line: .space LINE_SIZE
-.align 2
-
-# int begin
-# Begin cursor, points to the beginning of the line, it increases while the
-# line is being read.
-begin: .word 0
-
-# int end
-# End cursor, points to the end of the line.
-end: .word 0
-
-# int next
-# The next character to be read if any.
-# If the number is -1, then we reached EOF.
-# Otherwise, it stores the next 8 bit character in buffer.
-next: .word 0
-
-# bool full
-# True if there is a buffered character.
-full: .word 0
-
-# ==== .rodata ============================================================== #
-
-.section .rodata
-
-.align 2
-line_capacity: .word LINE_SIZE
-
-# ==== .text ================================================================ #
-
-.section .text
-
-# FUNCTION: int get_immediate ()
-# PARAMETERS: NONE
-# RETURNS: int a0 : -1 on EOF, otherwise the character read
-# DESCRIPTION: Read the next character without echoing it.
- .type get_immediate, @function
- .globl get_immediate
-get_immediate:
- addi sp, sp, -8
- sw ra, 0(sp)
- sw s0, 4(sp)
-
- la t0, next
- la t1, full
- lw t2, 0(t1)
- beq t2, zero, get_immediate_read_new # If not full read it.
-
- get_immediate_buffered:
- sw zero, 0(t1) # full = 0
- lw a0, 0(t0) # return next
- li t0, -1
- j get_immediate_end
-
- get_immediate_read_new:
- mv a0, zero
- la a1, next
- li a2, 1
- jal ra, read # read(0, &next, 1)
- beq zero, a0, get_immediate_eof
- # TODO: Check if UTF-8 valid string
- la t0, next # t0 = &next
- lb a0, 0(t0) # a0 = next
- j get_immediate_end
-
- get_immediate_eof:
- li a0, -1 # Return -1
-
- get_immediate_end:
- lw ra, 0(sp)
- lw s0, 4(sp)
- addi sp, sp, 8
- jr ra
-
-# FUNCTION: void put_immediate (char c)
-# PARAMETERS: a0 : char c
-# RETURNS: NONE
-# DESCRIPTION: Put a character immediately on the screen.
- .type put_immediate, @function
- .globl put_immediate
-put_immediate:
- addi sp, sp, -4
- sw ra, 0(sp)
-
- jal ra, put
- jal ra, synchronise
-
- lw ra, 0(sp)
- addi sp, sp, 4
- jr ra
-
-# FUNCTION: void put_zstring (char *str)
-# PARAMETERS: a0 : char *str
-# RETURNS: NONE
-# DESCRIPTION: Put a zero-terminated string on the screen.
- .type put_zstring, @function
- .globl put_zstring
-put_zstring:
- addi sp, sp, -8
- sw ra, 0(sp)
- sw s0, 4(sp)
-
- mv s0, a0
- put_zstring_loop:
- lb a0, 0(s0)
- beq a0, zero, put_zstring_end
- jal ra, put
- addi s0, s0, 1
- j put_zstring_loop
-
- put_zstring_end:
- mv a0, zero
- jal ra, synchronise
-
- lw ra, 0(sp)
- lw s0, 4(sp)
- addi sp, sp, 8
- jr ra
-
-# FUNCTION: void put_string (char *str, int length)
-# PARAMETERS: a0 : char *str
-# a1 : int length
-# RETURNS: NONE
-# DESCRIPTION: Put a `length' bytes long string on the screen.
- .type put_string, @function
- .globl put_string
-put_string:
- addi sp, sp, -12
- sw ra, 0(sp)
- sw s0, 4(sp)
- sw s1, 8(sp)
-
- mv s0, a0
- mv s1, a1
- put_string_loop:
- beq s1, zero, put_string_end
- lb a0, 0(s0)
- jal ra, put
- addi s0, s0, 1
- addi s1, s1, -1
- j put_string_loop
-
- put_string_end:
- jal ra, synchronise
-
- lw ra, 0(sp)
- lw s0, 4(sp)
- lw s1, 8(sp)
- addi sp, sp, 12
- jr ra
-
-# FUNCTION: void get_string (char *str, int length)
-# PARAMETERS: a0 : char *str
-# a1 : int length
-# RETURNS: NONE
-# DESCRIPTION: Read a `length' bytes long string.
- .type get_string, @function
- .globl get_string
-get_string:
- addi sp, sp, -12
- sw ra, 0(sp)
- sw s0, 4(sp)
- sw s1, 8(sp)
-
- mv s0, a0 # s0 = str
- mv s1, a1 # s1 = length
- get_string_loop:
- beq s1, zero, get_string_end # exit when length = 0
- jal ra, get_character # a0 = get_character()
- li t0, -1
- beq t0, a0, get_string_end # exit when EOF
- sw a0, 0(s0) # *s0 = a0
- addi s1, s1, -1
- addi s0, s0, 1
- j get_string_loop
-
- get_string_end:
- lw ra, 0(sp)
- lw s0, 4(sp)
- lw s1, 8(sp)
- addi sp, sp, 12
- jr ra
-
-# FUNCTION: int get_character ()
-# PARAMETERS: NONE
-# RETURNS: a0 : int
-# DESCRIPTION: Read one character from standard input
- .type get_character, @function
- .globl get_character
-get_character:
- addi sp, sp, -4
- sw ra, 0(sp)
-
- jal ra, refill
- la t0, begin
- la t1, line
- lw t2, 0(t0)
- add t3, t2, t1 # t2 = line + begin
- lb a0, 0(t3) # return *(line + begin)
- addi t2, t2, 1
- sw t2, 0(t0) # begin++
-
- lw ra, 0(sp)
- addi sp, sp, 4
- jr ra
-
-# FUNCTION: int peek_character ()
-# PARAMETERS: NONE
-# RETURNS: a0 : int
-# DESCRIPTION: Peek which will be the next character from standard input.
- .type peek_character, @function
- .globl peek_character
-peek_character:
- addi sp, sp, -4
- sw ra, 0(sp)
-
- jal ra, refill
- la t0, begin
- la t1, line
- lw t0, 0(t0)
- add t2, t1, t0
- lb a0, 0(t2)
-
- lw ra, 0(sp)
- addi sp, sp, 4
- jr ra
-
-# ==== Utility ==== #
-
-# FUNCTION: int peek ()
-# PARAMETERS: NONE
-# RETURNS: a0 : int ch
-# DESCRIPTION: It checks the next character (if any) and returns it. The next
-# time it is read or peeked, it returns the same character until
-# it is read.
- .type peek, @function
-peek:
- addi sp, sp, -4
- sw ra, 0(sp)
-
- la t1, full
- lw a1, 0(t1)
- bne a1, zero, peek_full # If full, goto peek_full
-
- peek_empty:
- jal ra, get_immediate
- la t1, full
- li a1, 1
- sw a1, 0(t1) # Fill it
-
- peek_full:
- la t0, next
- lw a0, 0(t0)
-
- lw ra, 0(sp)
- addi sp, sp, 4
- jr ra
-
-# FUNCTION: void read_line ()
-# PARAMETERS: NONE
-# RETURNS: NONE
-# DESCRIPTION: Reads full line.
- .type read_line, @function
-read_line:
- addi sp, sp, -24
- sw ra, 0(sp)
- sw s0, 4(sp)
- sw s1, 8(sp)
- sw s2, 12(sp)
- sw s3, 16(sp)
- sw s4, 20(sp)
-
- la s0, line # s0 (line)
- mv s1, zero # s1 (end)
- mv s2, zero # s2 (cursor)
-
- read_line_loop:
- jal ra, get_immediate
-
- li t0, -1 # EOF
- li t1, '\n' # LF
- li t2, '\r' # CR
- li t3, 27 # ESC
- li t4, '\b' # Backspace
-
- beq a0, t0, read_line_end # EOF
- beq a0, t1, read_line_LF # Line Feed
- beq a0, t2, read_line_CR # Carriage Return
- beq a0, t3, read_line_on_ESC # Escape Sequence
- beq a0, t4, read_line_on_DEL # Backspace
-
- read_line_normal:
- # Check line capacity
- la t0, line_capacity
- lw t0, 0(t0)
- addi t0, t0, -1
- bge s1, t0, read_line_loop # Line too long
-
- # Shift right the line
- mv t0, s1 # t0 = end
- add t1, s0, s1 # char *t1 = &line[end]
- read_line_shift_right:
- blt t0, s2, read_line_end_shift_right # exit when t0 = Cursor
- lb t2, 0(t1)
- sb t2, 1(t1)
- addi t1, t1, -1
- addi t0, t0, -1
- j read_line_shift_right
- read_line_end_shift_right:
-
- # Insert character
- add t0, s0, s2 # t0 = &line[cursor]
- sb a0, 0(t0) # line[cursor] = a0
- addi s1, s1, 1 # end++
- addi s2, s2, 1 # cursor++
-
- # Redraw
- add a0, s0, s2
- addi a0, a0, -1 # str = line + cursor - 1
- sub a1, s1, s2
- addi a1, a1, 1 # length = end - cursor + 1
- jal ra, put_string # put_string(t0, end - cursor + 1)
-
- # Move cursor back
- mv s3, s2 # s3 = cursor
- read_line_cursor_back:
- beq s3, s1, read_line_end_cursor_back
- la a0, go_left_str
- jal ra, put_zstring
- addi s3, s3, 1 # s3++
- j read_line_cursor_back
- read_line_end_cursor_back:
-
- j read_line_loop
-
- read_line_LF:
- add t0, s0, s1
- sb a0, 0(t0) # line[end] = '\n'
- addi s1, s1, 1
- jal ra, put_immediate
- j read_line_end
-
- read_line_CR:
- jal ra, peek
- li t0, '\n'
- beq t0, a0, read_line_CR_win
- read_line_CR_mac:
- mv a0, t0
- j read_line_LF
-
- read_line_CR_win:
- jal ra, get_immediate # Read it to skip it
- j read_line_LF
-
- read_line_on_ESC:
- jal ra, peek
- li t0, '['
- bne a0, t0, read_line_loop # Bad sequence
- jal ra, get_immediate
-
- jal ra, peek
- li t0, 'A'
- li t1, 'B'
- li t2, 'C'
- li t3, 'D'
-
- beq a0, t0, read_line_on_ESC_UP_DOWN
- beq a0, t1, read_line_on_ESC_UP_DOWN
- beq a0, t2, read_line_on_ESC_RIGHT
- beq a0, t3, read_line_on_ESC_LEFT
- j read_line_loop
-
- read_line_on_ESC_UP_DOWN:
- jal ra, get_immediate # Buffer it and ignore it.
- j read_line_loop
-
- read_line_on_ESC_LEFT:
- jal ra, get_immediate
- beq s2, zero, read_line_loop # Can't go to left.
- addi s2, s2, -1
- la a0, go_left_str
- jal ra, put_zstring
- j read_line_loop
-
- read_line_on_ESC_RIGHT:
- jal ra, get_immediate
- bge s2, s1, read_line_loop # Can't go right.
- addi s2, s2, 1
- la a0, go_right_str
- jal ra, put_zstring
- j read_line_loop
-
- read_line_on_DEL:
- beq s2, zero, read_line_loop # Cursor at the beginning
- beq s1, zero, read_line_loop # End at the beginning
-
- # Shift the string left
- jal ra, put # Go back, not immediate.
- addi s1, s1, -1 # end--
- addi s2, s2, -1 # cursor--
- mv s3, s2 # s3 = cursor
- add s4, s0, s2 # s4 = line + cursor
- read_line_shift_left:
- beq s3, s1, read_line_end_shift_left
- lb a0, 1(s4)
- sb a0, 0(s4) # *s4 = *(s4 + 1)
- jal ra, put # put(a0), Not buffered
- addi s3, s3, 1 # s3++
- addi s4, s4, 1 # s4++
- j read_line_shift_left
- read_line_end_shift_left:
- li a0, ' '
- jal ra, put
- li a0, '\b'
- jal ra, put_immediate
-
- # Return cursor to last position
- mv s3, s2 # s3 = cursor
- read_line_DEL_cursor_back:
- beq s3, s1, read_line_DEL_end_cursor_back
- la a0, go_left_str
- jal ra, put_zstring
- addi s3, s3, 1 # s3++
- j read_line_cursor_back
- read_line_DEL_end_cursor_back:
- j read_line_loop
-
- read_line_end:
-
- la t0, begin
- la t1, end
- sw zero, 0(t0) # begin = 0
- sw s1, 0(t1) # end = end
-
- lw ra, 0(sp)
- lw s0, 4(sp)
- lw s1, 8(sp)
- lw s2, 12(sp)
- lw s3, 16(sp)
- lw s4, 20(sp)
- addi sp, sp, 24
- jr ra
-
-# FUNCTION: void put (char c)
-# PARAMETERS: a0 : char c
-# RETURNS: NONE
-# DESCRIPTION: Put a character on the screen without synchronising. If the
-# character is a line feed (\n) it transforms it to (\r\n).
- .type put, @function
-put:
- addi sp, sp, -4
- sw ra, 0(sp)
-
- li t0, '\n'
- bne t0, a0, put_skip
-
- put_CR:
- li a0, '\r'
- jal ra, putchar
- li a0, '\n'
-
- put_skip:
- jal ra, putchar
-
- lw ra, 0(sp)
- addi sp, sp, 4
- jr ra
-
-# FUNCTION: void synchronise ()
-# PARAMETERS: NONE
-# RETURNS: NONE
-# DESCRIPTION: Flush and synchronise output
- .type synchronise, @function
-synchronise:
- addi sp, sp, -4
- sw ra, 0(sp)
-
- li a0, 1 # a0 = STDOUT
- jal ra, fsync
-
- lw ra, 0(sp)
- addi sp, sp, 4
- jr ra
-
-# FUNCTION: void refill ()
-# PARAMETERS: NONE
-# RETURNS: NONE
-# DESCRIPTION: Refill the line buffer if it is empty.
- .type refill, @function
-refill:
- addi sp, sp, -4
- sw ra, 0(sp)
-
- la t0, begin
- la t1, end
- lw t2, 0(t0)
- lw t3, 0(t1)
- sub t5, t3, t2 # t5 = end - begin
- blt zero, t5, refill_end # return when end - begin > 0
- jal ra, read_line # Otherwise re-read the line
-
- refill_end:
- lw ra, 0(sp)
- addi sp, sp, 4
- jr ra
-
-# ======== END OF FILE ====================================================== #
diff --git a/gateway/esp32-rv/main/rdcycle.s b/gateway/esp32-rv/main/rdcycle.s
index d4b39658d..0acef85cd 100644
--- a/gateway/esp32-rv/main/rdcycle.s
+++ b/gateway/esp32-rv/main/rdcycle.s
@@ -1,5 +1,5 @@
#
-# Copyright 2018-2025 Felix Garcia Carballeira, Alejandro Calderon Mateos, Diego Camarmas Alonso, José Antonio Verde Jiménez
+# Copyright 2018-2024 Felix Garcia Carballeira, Alejandro Calderon Mateos, Diego Camarmas Alonso, José Antonio Verde Jiménez
#
# This file is part of CREATOR.
#
diff --git a/gateway/esp32-rv/main/syscall/return_from_panic.S b/gateway/esp32-rv/main/syscall/return_from_panic.S
new file mode 100644
index 000000000..388407304
--- /dev/null
+++ b/gateway/esp32-rv/main/syscall/return_from_panic.S
@@ -0,0 +1,71 @@
+// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "riscv/rvruntime-frames.h"
+
+/* The riscv panic handler in components/riscv/vectors.S doesn't allow the panic
+ handler function to return.
+
+ However, for the purposes of this test we want to allow the panic handler to return.
+
+ There is functionality in vectors.S restore the CPU state, but it only
+ restores when CONTEXT_SIZE registers are
+ pushed onto the stack not RV_STK_FRMSZ registers
+
+ Instead of messing with that, implement a full "restore from RvExcFrame"
+ function here which restores the CPU and then
+ returns from exception.
+
+ Called as return_from_panic_handler(RvExcFrame *frame)
+*/
+.global return_from_panic_handler
+return_from_panic_handler:
+ or t0, a0, a0 /* use t0 as the working register */
+
+ /* save general registers */
+ lw ra, RV_STK_RA(t0)
+ lw sp, RV_STK_SP(t0)
+ lw gp, RV_STK_GP(t0)
+ lw tp, RV_STK_TP(t0)
+ lw s0, RV_STK_S0(t0)
+ lw s1, RV_STK_S1(t0)
+ lw a0, RV_STK_A0(t0)
+ lw a1, RV_STK_A1(t0)
+ lw a2, RV_STK_A2(t0)
+ lw a3, RV_STK_A3(t0)
+ lw a4, RV_STK_A4(t0)
+ lw a5, RV_STK_A5(t0)
+ lw a6, RV_STK_A6(t0)
+ lw a7, RV_STK_A7(t0)
+ lw s2, RV_STK_S2(t0)
+ lw s3, RV_STK_S3(t0)
+ lw s4, RV_STK_S4(t0)
+ lw s5, RV_STK_S5(t0)
+ lw s6, RV_STK_S6(t0)
+ lw s7, RV_STK_S7(t0)
+ lw s8, RV_STK_S8(t0)
+ lw s9, RV_STK_S9(t0)
+ lw s10, RV_STK_S10(t0)
+ lw s11, RV_STK_S11(t0)
+ lw t3, RV_STK_T3(t0)
+ lw t4, RV_STK_T4(t0)
+ lw t5, RV_STK_T5(t0)
+ lw t6, RV_STK_T6(t0)
+
+ lw t2, RV_STK_MEPC(t0)
+ csrw mepc, t2
+
+ lw t1, RV_STK_T1(t0)
+ lw t2, RV_STK_T2(t0)
+ lw t0, RV_STK_T0(t0)
+ mret
diff --git a/gateway/esp32-rv/main/syscall/test_panic.c b/gateway/esp32-rv/main/syscall/test_panic.c
new file mode 100644
index 000000000..9dc1242a7
--- /dev/null
+++ b/gateway/esp32-rv/main/syscall/test_panic.c
@@ -0,0 +1,266 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * Panic handler wrapper in order to simulate ecalls in CREATOR using Espressif family
+ * Author: Elisa Utrilla Arroyo
+ *
+ */
+
+
+#include "riscv/rvruntime-frames.h"
+#include "esp_private/panic_internal.h"
+#include "esp_private/panic_reason.h"
+#include "hal/wdt_hal.h"
+#include "soc/timer_group_struct.h"
+#include "soc/timer_group_reg.h"
+#include "esp_rom_sys.h"
+#include "esp_attr.h"
+#include
+#include "rom/uart.h"
+#include "esp_task_wdt.h"
+
+#define POOL_CAPACITY 65536 // 64 KB poolç
+char memory_pool[POOL_CAPACITY];
+int current_offset = 0;
+
+void disable_all_hw_watchdogs() {
+ // TG0
+ TIMERG0.wdtwprotect.val = 0x50D83AA1;
+ TIMERG0.wdtconfig0.val = 0;
+ TIMERG0.wdtwprotect.val = 0;
+
+ // TG1
+ TIMERG1.wdtwprotect.val = 0x50D83AA1;
+ TIMERG1.wdtconfig0.val = 0;
+ TIMERG1.wdtwprotect.val = 0;
+}
+
+extern void esp_panic_handler(panic_info_t *info);
+volatile bool g_override_ecall = true;
+
+void __real_esp_panic_handler(panic_info_t *info);
+
+
+void return_from_panic_handler(RvExcFrame *frm) __attribute__((noreturn));
+// -------------Read int from UART0
+static char buffer_int[16];
+static int idx = 0;
+
+int read_buffer_int(){
+ unsigned char c = '\0';
+
+ uart_rx_one_char(&c);
+ //Is an space?? Finish it!!
+ if (c == '\n' || c == '\r') {
+ buffer_int[idx++] = '\0';
+ esp_rom_printf("\n"); //echo
+ if (idx > 0) //Buffer has things
+ {
+ idx = 0;
+ return 0;
+ }
+ else{ return -1; }
+
+ }
+ //Number: wait until another num comes up OR a \n
+ if (isdigit(c)) {
+ if (idx < sizeof(buffer_int) - 1) {
+ buffer_int[idx] = c;
+ esp_rom_printf("%c", c);
+ idx++;
+ return -1;
+ }
+ }
+ //TODO: Protocol for char instead of number
+
+ return -1;
+}
+int read_int(){
+ int value = 0;
+ int i = -1;
+ int sum = 0;
+ while (i == -1){
+ i = read_buffer_int();
+ if (i == -1){
+ //
+ for (int x =1;x< 1000; x++){
+ sum ++;
+
+ }
+ }
+ }
+ // Transform into number
+ for (int z = 0; buffer_int[z] != '\0'; z++) {
+ value = value * 10 + (buffer_int[z] - '0');
+ }
+ memset(buffer_int, 0, sizeof(buffer_int));
+ return value;
+
+}
+//------------- Read char from UART0
+char read_buffer_char(){
+ unsigned char c = '\0';
+ //esp_rom_printf("Value: %c",c);
+
+ uart_rx_one_char(&c);
+ if (c != '\0') {
+ esp_rom_printf("%c", c);
+ return c;
+ }
+ else{ return '\0'; }
+
+ return -1;
+}
+
+char read_char() {
+ char value = '\0';
+ int sum =0;
+ while (value == '\0'){
+ value = read_buffer_char();
+ if (value == '\0'){
+ for (int x =1;x< 1000; x++){
+ sum ++;
+
+ }
+ }
+ }
+ return value;
+}
+//------------- Read string from UART0
+int read_buffer_string(char *dest, int length){
+ unsigned char c = '\0';
+
+ uart_rx_one_char(&c);
+ //Is an space?? Finish it!!
+ if (c == '\n' || c == '\r') {
+ dest[idx++] = '\0';
+ esp_rom_printf("\n"); //echo
+ if (idx > 0 || idx >= length) //Buffer has things or surpass the length
+ {
+ idx = 0;
+ return 0;
+ }
+ else{ return -1; }
+
+ }
+ //Wait until another char comes
+ if (c != '\0') {
+ if (idx < length) {
+ dest[idx] = c;
+ esp_rom_printf("%c", c);
+ idx++;
+ return -1;
+ }
+ }
+ //TODO: Protocol for char instead of number
+
+ return -1;
+}
+
+void read_string(char *dest, int length) {
+ int i = -1;
+ int sum = 0;
+ while (i == -1){
+ i = read_buffer_string(dest,length);
+ if (i == -1){
+ //
+ for (int x =1;x< 1000; x++){
+ sum ++;
+
+ }
+ }
+ }
+}
+
+IRAM_ATTR void __wrap_esp_panic_handler(panic_info_t *info)
+{
+ RvExcFrame *frm = (RvExcFrame *)info->frame;
+ if ((frm->mcause == 0x0000000b || frm->mcause == 0x00000008) && g_override_ecall == true) { //Only catches Ecall syscalls
+ disable_all_hw_watchdogs();
+ int cause = frm->a7;
+ //esp_rom_printf("Causa del panic (a7): %d\n", cause);
+ switch (cause) {
+ case 1: { //Print int
+ int value = frm->a0;
+ esp_rom_printf("%d\n", value);
+ break;
+ }
+ case 2: { //Print float TODO
+ esp_rom_printf("\033[1;31mFloat number operations not registered yet\033[0m\n");
+ break;
+ }
+ case 3: { //Print double TODO
+ esp_rom_printf("\033[1;31mDouble number operations not registered yet\033[0m\n");
+ break;
+ }
+ case 4: { //Print string
+ char* cadena = (char*) frm->a0;
+ esp_rom_printf("%s\n", cadena);
+ break;
+ }
+ case 5: { // Read int
+ int number_read = read_int();
+ frm->a0 = number_read;
+ break;
+ }
+ case 6:{ // Read float TODO
+ esp_rom_printf("\033[1;31mFloat number operations not registered yet\033[0m\n");
+ break;
+ }
+ case 7:{ //Read double TODO
+ esp_rom_printf("\033[1;31mDouble number operations not registered yet\033[0m\n");
+ break;
+ }
+ case 8:{ //Read string
+ char* dest = (char*) frm->a0;
+ int length = frm->a1;
+ read_string(dest,length);
+ break;
+ }
+ case 9: { // sbrk
+ int increment = frm->a0;
+ if (current_offset + increment > POOL_CAPACITY || current_offset + increment < 0) {
+ frm->a0 = -1; // Offlimits
+ esp_rom_printf("\033[31;1mSBRK: Memory exhausted\033[0m\n");
+ } else {
+ char *prev_brk = &memory_pool[current_offset];
+ current_offset += increment;
+ frm->a0 = (int)prev_brk;
+ }
+ break;
+ }
+ case 10: { //exit
+ break;
+ }
+ case 11:{ //Print char
+ char caract = (char) frm->a0;
+ esp_rom_printf("%c\n", caract);
+ break;
+ }
+ case 12:{ //Read char
+ char char_leido = read_char();
+ frm->a0 = char_leido;
+ break;
+ }
+ default:
+ esp_rom_printf("Not an ecall registered\n");
+ break;
+ }
+
+
+ //frm->mepc = frm->ra;
+ if (cause == 10)
+ {
+ frm->mepc = frm->ra;
+ }
+ else
+ {
+ frm->mepc += 4;
+ }
+
+ return_from_panic_handler(frm);
+ } else {
+ __real_esp_panic_handler(info); //Other fatal errors are treated as usual
+ }
+}
\ No newline at end of file
diff --git a/gateway/esp32-rv/openocd_scripts/openscript_esp32c3.cfg b/gateway/esp32-rv/openocd_scripts/openscript_esp32c3.cfg
new file mode 100644
index 000000000..837d99cd9
--- /dev/null
+++ b/gateway/esp32-rv/openocd_scripts/openscript_esp32c3.cfg
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Example OpenOCD configuration file for ESP32-C3 connected via builtin USB-JTAG adapter.
+#
+# For example, OpenOCD can be started for ESP32-C3 debugging on
+#
+# openocd -f board/esp32c3-builtin.cfg
+## Source the JTAG interface configuration file
+source [find interface/esp_usb_jtag.cfg]
+# Source the ESP32-C3 configuration file
+source [find target/esp32c3.cfg]
+# Inicializar target
+init
+reset halt
diff --git a/gateway/esp32-rv/openocd_scripts/openscript_esp32c6.cfg b/gateway/esp32-rv/openocd_scripts/openscript_esp32c6.cfg
new file mode 100644
index 000000000..41e3f6c49
--- /dev/null
+++ b/gateway/esp32-rv/openocd_scripts/openscript_esp32c6.cfg
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Example OpenOCD configuration file for ESP32-C3 connected via builtin USB-JTAG adapter.
+#
+# For example, OpenOCD can be started for ESP32-C3 debugging on
+#
+# openocd -f board/esp32c3-builtin.cfg
+## Source the JTAG interface configuration file
+source [find interface/esp_usb_jtag.cfg]
+# Source the ESP32-C3 configuration file
+source [find target/esp32c6.cfg]
+# Inicializar target
+init
+reset halt
diff --git a/gateway/esp32-rv/openscript.cfg b/gateway/esp32-rv/openscript.cfg
new file mode 100644
index 000000000..837d99cd9
--- /dev/null
+++ b/gateway/esp32-rv/openscript.cfg
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Example OpenOCD configuration file for ESP32-C3 connected via builtin USB-JTAG adapter.
+#
+# For example, OpenOCD can be started for ESP32-C3 debugging on
+#
+# openocd -f board/esp32c3-builtin.cfg
+## Source the JTAG interface configuration file
+source [find interface/esp_usb_jtag.cfg]
+# Source the ESP32-C3 configuration file
+source [find target/esp32c3.cfg]
+# Inicializar target
+init
+reset halt
diff --git a/gateway/esp32-rv/problems/TROUBLESHOOTING_ARCH.md b/gateway/esp32-rv/problems/TROUBLESHOOTING_ARCH.md
new file mode 100644
index 000000000..32a8a7ede
--- /dev/null
+++ b/gateway/esp32-rv/problems/TROUBLESHOOTING_ARCH.md
@@ -0,0 +1,57 @@
+# Troubleshooting
+Logs are generated on the `openocd.log` file.
+
+Sometaimes, you can just unplug, replug and run again, or refresh the GDBGUI
+page. If it shows another type of issue, please send it to the official page.
+Feedback makes us grow :).
+
+
+## Error: `gdb_exception_error` -- `libusb_bulk_write error: LIBUSB_ERROR_NO_DEVICE`
+
+This problem happens because the user doesn't have permission to write to
+the JTAG USB device, located in `/dev/bus/usb/003/XXX` (where `XXX` is a
+pseudo-random number).
+
+You can check this by doing:
+
+```sh
+ls -lah /dev/bus/usb/003
+```
+
+```sh
+total 0
+drwxr-xr-x 2 root root 180 Oct 1 11:03 .
+drwxr-xr-x 6 root root 120 Oct 1 10:36 ..
+crw-rw-r-- 1 root root 189, 256 Oct 1 10:41 001
+...
+crw-rw-r-- 1 root root 189, 256 Oct 1 10:41 022
+```
+
+You can see the user and group are `root`.
+
+To change this, we can configure udev so that, when it mounts the JTAG
+device it gives it the group permissions it typically gives to all other
+devices (`uucp` for Arch, `dialout` for Ubuntu).
+
+> [!TIP]
+> Obviously, you must make sure your user belongs to that group.
+
+> [!TIP]
+> To see the device's id, run `lsusb`:
+>
+> ```
+> ...
+> Bus 003 Device 022: ID 303a:1001 Espressif USB JTAG/serial debug unit
+> ...
+> ```
+>
+> Therefore, the vendor id is `303a`, and the product id is `1001`.
+
+Create a new `/etc/udev/rules.d/99-Espressif.rules` file (with `sudo`!), containing:
+
+```udev
+# Set default permisions when mounting Espressif USB JTAG/serial debug unit
+# (set to `uucp' usergroup)
+
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", GROUP="uucp"
+```
diff --git a/gateway/esp32-rv/tests/random.s b/gateway/esp32-rv/tests/random.s
index 8eca81744..f8384c09f 100644
--- a/gateway/esp32-rv/tests/random.s
+++ b/gateway/esp32-rv/tests/random.s
@@ -1,5 +1,5 @@
#
-# Copyright 2018-2025 Felix Garcia Carballeira, Alejandro Calderon Mateos, Diego Camarmas Alonso, José Antonio Verde Jiménez
+# Copyright 2018-2024 Felix Garcia Carballeira, Alejandro Calderon Mateos, Diego Camarmas Alonso, José Antonio Verde Jiménez
#
# This file is part of CREATOR.
#
diff --git a/gateway/esp32-rv/tests/random_array.s b/gateway/esp32-rv/tests/random_array.s
index f488ce28e..4cc218b95 100644
--- a/gateway/esp32-rv/tests/random_array.s
+++ b/gateway/esp32-rv/tests/random_array.s
@@ -1,5 +1,5 @@
#
-# Copyright 2018-2025 Felix Garcia Carballeira, Alejandro Calderon Mateos, Diego Camarmas Alonso, José Antonio Verde Jiménez
+# Copyright 2018-2024 Felix Garcia Carballeira, Alejandro Calderon Mateos, Diego Camarmas Alonso, José Antonio Verde Jiménez
#
# This file is part of CREATOR.
#
diff --git a/gateway/esp32-rv/tests/sleep.s b/gateway/esp32-rv/tests/sleep.s
index 614b70daf..f34f42fe6 100644
--- a/gateway/esp32-rv/tests/sleep.s
+++ b/gateway/esp32-rv/tests/sleep.s
@@ -1,5 +1,5 @@
#
-# Copyright 2018-2025 Felix Garcia Carballeira, Alejandro Calderon Mateos, Diego Camarmas Alonso, José Antonio Verde Jiménez
+# Copyright 2018-2024 Felix Garcia Carballeira, Alejandro Calderon Mateos, Diego Camarmas Alonso, José Antonio Verde Jiménez
#
# This file is part of CREATOR.
#
diff --git a/gateway/esp32c2.zip b/gateway/esp32c2.zip
index 76470e145..eed34a4b9 100644
Binary files a/gateway/esp32c2.zip and b/gateway/esp32c2.zip differ
diff --git a/gateway/esp32c3.zip b/gateway/esp32c3.zip
index 4aa2f727c..84feeaf86 100644
Binary files a/gateway/esp32c3.zip and b/gateway/esp32c3.zip differ
diff --git a/gateway/esp32c6.zip b/gateway/esp32c6.zip
index bf22deb28..12aaca2ce 100644
Binary files a/gateway/esp32c6.zip and b/gateway/esp32c6.zip differ
diff --git a/gateway/esp32h2.zip b/gateway/esp32h2.zip
index eebc0181d..4ef946f94 100644
Binary files a/gateway/esp32h2.zip and b/gateway/esp32h2.zip differ
diff --git a/gateway/esp32s2.zip b/gateway/esp32s2.zip
index 584eaa302..433172538 100644
Binary files a/gateway/esp32s2.zip and b/gateway/esp32s2.zip differ
diff --git a/gateway/esp32s3.zip b/gateway/esp32s3.zip
index f22d27404..7b4157b0c 100644
Binary files a/gateway/esp32s3.zip and b/gateway/esp32s3.zip differ