diff --git a/components/simulator/creator_uielto_target_flash.js b/components/simulator/creator_uielto_target_flash.js index be64d9b54..d651e4e35 100644 --- a/components/simulator/creator_uielto_target_flash.js +++ b/components/simulator/creator_uielto_target_flash.js @@ -43,7 +43,7 @@ remote_target_boards = [ { text: 'Please select an option', value: "", disabled: true }, - { text: 'ESP32-C2 (RISC-V)', value: 'esp32c2' }, + { text: 'ESP32-C6 (RISC-V)', value: 'esp32c6' }, { text: 'ESP32-C3 (RISC-V)', value: 'esp32c3' }, { text: 'ESP32-H2 (RISC-V)', value: 'esp32h2' }, //{ text: 'ESP32-S2 (MIPS-32)', value: 'esp32s2' }, @@ -68,7 +68,7 @@ target_boards = [ { text: 'Please select an option', value: "", disabled: true }, - { text: 'ESP32-C2 (RISC-V)', value: 'esp32c2' }, + { text: 'ESP32-C6 (RISC-V)', value: 'esp32c6' }, { text: 'ESP32-C3 (RISC-V)', value: 'esp32c3' }, { text: 'ESP32-H2 (RISC-V)', value: 'esp32h2' }, //{ text: 'ESP32-S2 (MIPS-32)', value: 'esp32s2' }, @@ -83,8 +83,15 @@ flash_url = "http://localhost:8080", */ - flashing = false, - running = false, + + flashing = false, + running = false, + debugging = false, + fullclean = false, + stoprunning = false, + eraseflash = false, + showPopup: false, + pendingAction: null, } }, @@ -249,8 +256,7 @@ //Google Analytics creator_ga('simulator', 'simulator.download_driver', 'simulator.download_driver'); }, - - do_flash( ) + do_flash( ) { this.save(); @@ -271,19 +277,54 @@ this_env = this; gateway_remote_flash(this.flash_url + "/flash", farg).then( function(data) { - this_env.flashing = false; - show_notification(data, 'danger') ; - } ) ; + this_env.flashing = false; + console.log(JSON.stringify(data, null, 2)); + if (JSON.stringify(data, null, 2).includes('Flash completed successfully')) { + show_notification('Flashing program success.', 'success'); + } + if (JSON.stringify(data, null, 2).includes('No UART port found')) { + show_notification('Error flashing: Not found UART port', 'danger'); + } + } ) ; //Google Analytics creator_ga('simulator', 'simulator.flash', 'simulator.flash'); }, + do_stop_monitor() + { + + this.save(); + + this.stoprunning = true; + + var farg = { + target_board: this.target_board, + target_port: this.target_port, + assembly: code_assembly, + } ; + + this_env = this; + gateway_remote_monitor(this.flash_url + "/stopmonitor", farg).then( function(data) { + this_env.stoprunning = false; + //show_notification(data, 'danger') ; + console.log(JSON.stringify(data, null, 2)); + if (JSON.stringify(data, null, 2).includes('Process stopped')) { + show_notification('Process stopped.', 'success'); + } + } ) ; + + //Google Analytics + creator_ga('simulator', 'simulator.stopmonitor', 'simulator.stopmonitor'); + + }, + do_monitor( ) { this.save(); this.running = true; + this.stoprunning = false; var farg = { target_board: this.target_board, @@ -293,14 +334,121 @@ this_env = this; gateway_remote_monitor(this.flash_url + "/monitor", farg).then( function(data) { - this_env.running = false; - //show_notification(data, 'danger') ; + this_env.running = false; + console.log(JSON.stringify(data, null, 2)); + if (JSON.stringify(data, null, 2).includes('No UART port found')) { + show_notification('Error: Not found UART port', 'danger'); + } + if (JSON.stringify(data, null, 2).includes('No ELF file found')) { + show_notification('Error: Built proyect not found', 'danger'); + } } ) ; //Google Analytics creator_ga('simulator', 'simulator.monitor', 'simulator.monitor'); }, + + do_debug( ) + { + this.save(); + + this.debugging = true; + + var farg = { + target_board: this.target_board, + target_port: this.target_port, + assembly: code_assembly, + } ; + + this_env = this; + gateway_remote_monitor(this.flash_url + "/debug", farg).then( function(data) { + this_env.debugging = false; + if (JSON.stringify(data, null, 2).includes('No ELF file found in build directory')) { + show_notification('Error: Not found proyect to debug', 'danger'); + } + if (JSON.stringify(data, null, 2).includes('No JTAG found')) { + show_notification('Error: JTAG no connected. Check wire installment', 'danger'); + } + if (JSON.stringify(data, null, 2).includes('No UART found')) { + show_notification('Error: UART no connected. Check wire installment', 'danger'); + } + } ) ; + + //Google Analytics + creator_ga('simulator', 'simulator.debug', 'simulator.debug'); + }, + + showConfirmPopup(action) { + this.pendingAction = action; + this.showPopup = true; + }, + + confirmAction() { + this.showPopup = false; + if (this.pendingAction === 'fullclean') { + this.do_fullclean(); + } else if (this.pendingAction === 'eraseflash') { + this.do_erase_flash(); + } + this.pendingAction = null; + }, + + do_fullclean( ) + { + this.save(); + + this.fullclean = true; + + var farg = { + target_board: this.target_board, + target_port: this.target_port, + assembly: code_assembly, + } ; + + this_env = this; + gateway_remote_monitor(this.flash_url + "/fullclean", farg).then( function(data) { + this_env.fullclean = false; + console.log(JSON.stringify(data, null, 2)); + if (JSON.stringify(data, null, 2).includes('Full clean done.')) { + show_notification('Full clean done.', 'success'); + } + if (JSON.stringify(data, null, 2).includes('Nothing to clean')) { + show_notification('Nothing to clean', 'success'); + } + + } ) ; + + //Google Analytics + creator_ga('simulator', 'simulator.fullclean', 'simulator.fullclean'); + }, + do_erase_flash( ) + { + this.save(); + this.eraseflash = true; + + var farg = { + target_board: this.target_board, + target_port: this.target_port, + assembly: code_assembly, + } ; + + this_env = this; + gateway_remote_monitor(this.flash_url + "/eraseflash", farg).then( function(data) { + this_env.eraseflash = false; + //show_notification(data, 'danger') ; + console.log(JSON.stringify(data, null, 2)); + if (JSON.stringify(data, null, 2).includes('Erase flash done')) { + show_notification('Erase flash done. Please, unplug and plug the cable(s) again', 'success'); + } + if (JSON.stringify(data, null, 2).includes('Could not open /dev/ttyUSB0, the port is busy or doesn\'t exist')) { + show_notification('Error erasing flash: Hint: Check if the port is correct and ESP connected', 'danger'); + } + } ) ; + + //Google Analytics + creator_ga('simulator', 'simulator.eraseflash', 'simulator.eraseflash'); + }, // //General // @@ -534,12 +682,45 @@ ' ' + ' ' + ' ' + - ' ' + + ' ' + ' ' + ' ' + ' ' + ' ' + - ' Follow the instructions from: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/' + + ' Follow the instructions from: https://github.com/espressif/esp-idf/releases/tag/v5.3.2' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' How to install Python 3.9:' + + '
' +
+                                                        'sudo apt install software-properties-common\n' +
+                                                        'sudo add-apt-repository ppa:deadsnakes/ppa\n' +
+                                                        'sudo apt install python3.9' +
+                    '                                  
' + + ' ' + + '
' + + ' 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...' + + ' ' + + ' ' + + + ' ' + + ' ' + + '

This action will delete your previous work. Are you sure you want to proceed?

' + + ' ' + + '
' + + + '
' + + '
' + + + // 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