aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErhan Kurubas <erhan.kurubas@espressif.com>2023-04-14 00:07:18 +0200
committerAntonio Borneo <borneo.antonio@gmail.com>2023-05-27 06:38:51 +0000
commita0fecd6c41a6f2c965352efb0df70a149b7b260c (patch)
tree6f76b8be9eebed69c12cc916347ef2253d8b6831
parent144d940a8b0276d2ecb97ee6615d8a78faf4117d (diff)
downloadriscv-openocd-a0fecd6c41a6f2c965352efb0df70a149b7b260c.zip
riscv-openocd-a0fecd6c41a6f2c965352efb0df70a149b7b260c.tar.gz
riscv-openocd-a0fecd6c41a6f2c965352efb0df70a149b7b260c.tar.bz2
target/espressif: add system level tracing feature
Produces traces compatible with SEGGER SystemView tool. Signed-off-by: Erhan Kurubas <erhan.kurubas@espressif.com> Change-Id: If1057309edbb91ed2cf1ebf9137c378d3deb9b88 Reviewed-on: https://review.openocd.org/c/openocd/+/7606 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
-rw-r--r--doc/openocd.texi34
-rw-r--r--src/target/espressif/Makefile.am3
-rw-r--r--src/target/espressif/esp32_apptrace.c297
-rw-r--r--src/target/espressif/esp32_sysview.c554
-rw-r--r--src/target/espressif/esp32_sysview.h38
-rw-r--r--src/target/espressif/segger_sysview.h79
6 files changed, 988 insertions, 17 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi
index d0bc3f9..9b485c5 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -11271,6 +11271,40 @@ w/o OpenOCD command and keeps only the latest data window which fit into the buf
Data will be stored to specified destination.
@end deffn
+@deffn {Command} {esp sysview} (start file://<outfile1> [file://<outfile2>] [<poll_period> [<trace_size> [<stop_tmo> [<wait4halt> [<skip_size>]]]]])
+Starts @uref{https://www.segger.com/products/development-tools/systemview/, SEGGER SystemView}
+compatible tracing. Data will be stored to specified destination.
+For dual-core chips traces from every core will be saved to separate files.
+Resulting files can be open in "SEGGER SystemView" application.
+@url{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#openocd-systemview-tracing-command-options}
+The meaning of the arguments is identical to @command{esp apptrace start}.
+@end deffn
+
+@deffn {Command} {esp sysview} (stop)
+Stops SystremView compatible tracing started with above command.
+@url{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#openocd-systemview-tracing-command-options}
+@end deffn
+
+@deffn {Command} {esp sysview} (status)
+Requests ongoing SystremView compatible tracing status.
+@url{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#openocd-systemview-tracing-command-options}
+@end deffn
+
+@deffn {Command} {esp sysview_mcore} (start file://<outfile> [<poll_period> [<trace_size> [<stop_tmo> [<wait4halt> [<skip_size>]]]]])
+This command is identical to @command{esp sysview start}, but uses Espressif multi-core extension to
+@uref{https://www.segger.com/products/development-tools/systemview/, SEGGER SystemView} data format.
+Data will be stored to specified destination. Tracing data from all cores are saved in the same file.
+The meaning of the arguments is identical to @command{esp sysview start}.
+@end deffn
+
+@deffn {Command} {esp sysview_mcore} (stop)
+Stops Espressif multi-core SystremView tracing started with above command.
+@end deffn
+
+@deffn {Command} {esp sysview_mcore} (status)
+Requests ongoing Espressif multi-core SystremView tracing status.
+@end deffn
+
@anchor{softwaredebugmessagesandtracing}
@section Software Debug Messages and Tracing
@cindex Linux-ARM DCC support
diff --git a/src/target/espressif/Makefile.am b/src/target/espressif/Makefile.am
index c1759ed..14625d4 100644
--- a/src/target/espressif/Makefile.am
+++ b/src/target/espressif/Makefile.am
@@ -15,5 +15,8 @@ noinst_LTLIBRARIES += %D%/libespressif.la
%D%/esp32.c \
%D%/esp32s2.c \
%D%/esp32s3.c \
+ %D%/esp32_sysview.c \
+ %D%/esp32_sysview.h \
+ %D%/segger_sysview.h \
%D%/esp_semihosting.c \
%D%/esp_semihosting.h
diff --git a/src/target/espressif/esp32_apptrace.c b/src/target/espressif/esp32_apptrace.c
index 291503e..0c510ff 100644
--- a/src/target/espressif/esp32_apptrace.c
+++ b/src/target/espressif/esp32_apptrace.c
@@ -32,6 +32,8 @@
#include "esp_xtensa_smp.h"
#include "esp_xtensa_apptrace.h"
#include "esp32_apptrace.h"
+#include "esp32_sysview.h"
+#include "segger_sysview.h"
#define ESP32_APPTRACE_USER_BLOCK_CORE(_v_) ((_v_) >> 15)
#define ESP32_APPTRACE_USER_BLOCK_LEN(_v_) ((_v_) & ~BIT(15))
@@ -82,6 +84,8 @@ static int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx *ctx,
static struct esp32_apptrace_block *esp32_apptrace_free_block_get(struct esp32_apptrace_cmd_ctx *ctx);
static int esp32_apptrace_handle_trace_block(struct esp32_apptrace_cmd_ctx *ctx,
struct esp32_apptrace_block *block);
+static int esp32_sysview_start(struct esp32_apptrace_cmd_ctx *ctx);
+static int esp32_sysview_stop(struct esp32_apptrace_cmd_ctx *ctx);
static const bool s_time_stats_enable = true;
@@ -1118,10 +1122,7 @@ static int esp32_apptrace_poll(void *priv)
return ERROR_FAIL;
}
}
- res =
- ctx->hw->data_read(ctx->cpus[fired_target_num],
- target_state[fired_target_num].data_len,
- block->data,
+ res = ctx->hw->data_read(ctx->cpus[fired_target_num], target_state[fired_target_num].data_len, block->data,
target_state[fired_target_num].block_id,
/* do not ack target data in sync mode,
esp32_apptrace_handle_trace_block() can write response data and will do ack thereafter */
@@ -1215,6 +1216,11 @@ static int esp32_apptrace_poll(void *priv)
return ERROR_OK;
}
+static inline bool is_sysview_mode(int mode)
+{
+ return mode == ESP_APPTRACE_CMD_MODE_SYSVIEW || mode == ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE;
+}
+
static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx)
{
if (duration_measure(&ctx->read_time) != 0)
@@ -1222,7 +1228,12 @@ static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx)
int res = target_unregister_timer_callback(esp32_apptrace_poll, ctx);
if (res != ERROR_OK)
LOG_ERROR("Failed to unregister target timer handler (%d)!", res);
-
+ if (is_sysview_mode(ctx->mode)) {
+ /* stop tracing */
+ res = esp32_sysview_stop(ctx);
+ if (res != ERROR_OK)
+ LOG_ERROR("sysview: Failed to stop tracing!");
+ }
/* data processor is alive, so wait for all received blocks to be processed */
res = esp32_apptrace_wait_tracing_finished(ctx);
if (res != ERROR_OK)
@@ -1236,6 +1247,190 @@ static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx)
LOG_ERROR("Failed to cleanup cmd ctx (%d)!", res);
}
+/* this function must be called after connecting to targets */
+static int esp32_sysview_start(struct esp32_apptrace_cmd_ctx *ctx)
+{
+ uint8_t cmds[] = { SEGGER_SYSVIEW_COMMAND_ID_START };
+ uint32_t fired_target_num = 0;
+ struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM];
+ struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
+
+ /* get current block id */
+ int res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num);
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to read target data info!");
+ return res;
+ }
+ if (fired_target_num == UINT32_MAX) {
+ /* it can happen that there is no pending target data, but block was switched
+ * in this case block_ids on both CPUs are equal, so select the first one */
+ fired_target_num = 0;
+ }
+ /* start tracing */
+ res = esp_apptrace_usr_block_write(ctx->hw, ctx->cpus[fired_target_num], target_state[fired_target_num].block_id,
+ cmds, sizeof(cmds));
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to start tracing!");
+ return res;
+ }
+ cmd_data->sv_trace_running = 1;
+ return res;
+}
+
+static int esp32_sysview_stop(struct esp32_apptrace_cmd_ctx *ctx)
+{
+ uint32_t old_block_id, fired_target_num = 0, empty_target_num = 0;
+ struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM];
+ struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
+ uint8_t cmds[] = { SEGGER_SYSVIEW_COMMAND_ID_STOP };
+ struct duration wait_time;
+
+ struct esp32_apptrace_block *block = esp32_apptrace_free_block_get(ctx);
+ if (!block) {
+ LOG_ERROR("Failed to get free block for data on (%s)!", target_name(ctx->cpus[fired_target_num]));
+ return ERROR_FAIL;
+ }
+
+ /* halt all CPUs (not only one), otherwise it can happen that there is no target data and
+ * while we are queueing commands another CPU switches tracing block */
+ int res = esp32_apptrace_safe_halt_targets(ctx, target_state);
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to halt targets (%d)!", res);
+ return res;
+ }
+ /* it can happen that there is no pending target data
+ * in this case block_ids on both CPUs are equal, so the first one will be selected */
+ for (unsigned int k = 0; k < ctx->cores_num; k++) {
+ if (target_state[k].data_len) {
+ fired_target_num = k;
+ break;
+ }
+ }
+ if (target_state[fired_target_num].data_len) {
+ /* read pending data without ack, they will be acked when stop command is queued */
+ res = ctx->hw->data_read(ctx->cpus[fired_target_num], target_state[fired_target_num].data_len, block->data,
+ target_state[fired_target_num].block_id,
+ false /*no ack target data*/);
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to read data on (%s)!", target_name(ctx->cpus[fired_target_num]));
+ return res;
+ }
+ /* process data */
+ block->data_len = target_state[fired_target_num].data_len;
+ res = esp32_apptrace_handle_trace_block(ctx, block);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len);
+ return res;
+ }
+ }
+ /* stop tracing and ack target data */
+ res = esp_apptrace_usr_block_write(ctx->hw, ctx->cpus[fired_target_num], target_state[fired_target_num].block_id,
+ cmds,
+ sizeof(cmds));
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to stop tracing!");
+ return res;
+ }
+ if (ctx->cores_num > 1) {
+ empty_target_num = fired_target_num ? 0 : 1;
+ /* ack target data on another CPU */
+ res = ctx->hw->ctrl_reg_write(ctx->cpus[empty_target_num], target_state[fired_target_num].block_id,
+ 0 /*target data ack*/,
+ true /*host connected*/,
+ false /*no host data*/);
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to ack data on target '%s' (%d)!",
+ target_name(ctx->cpus[empty_target_num]), res);
+ return res;
+ }
+ }
+ /* resume targets to allow command processing */
+ LOG_INFO("Resume targets");
+ bool smp_resumed = false;
+ for (unsigned int k = 0; k < ctx->cores_num; k++) {
+ if (smp_resumed && ctx->cpus[k]->smp) {
+ /* in SMP mode we need to call target_resume for one core only */
+ continue;
+ }
+ res = target_resume(ctx->cpus[k], 1, 0, 1, 0);
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to resume target '%s' (%d)!", target_name(ctx->cpus[k]), res);
+ return res;
+ }
+ if (ctx->cpus[k]->smp)
+ smp_resumed = true;
+ }
+ /* wait for block switch (command sent), so we can disconnect from targets */
+ old_block_id = target_state[fired_target_num].block_id;
+ if (duration_start(&wait_time) != 0) {
+ LOG_ERROR("Failed to start trace stop timeout measurement!");
+ return ERROR_FAIL;
+ }
+ /* we are waiting for the last data from tracing block and also there can be data in the pended
+ * data buffer */
+ /* so we are expecting two TRX block switches at most or stopping due to timeout */
+ while (cmd_data->sv_trace_running) {
+ res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num);
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to read targets data info!");
+ return res;
+ }
+ if (fired_target_num == UINT32_MAX) {
+ /* it can happen that there is no pending (last) target data, but block was
+ * switched */
+ /* in this case block_ids on both CPUs are equal, so select the first one */
+ fired_target_num = 0;
+ }
+ if (target_state[fired_target_num].block_id != old_block_id) {
+ if (target_state[fired_target_num].data_len) {
+ /* read last data and ack them */
+ res = ctx->hw->data_read(ctx->cpus[fired_target_num],
+ target_state[fired_target_num].data_len,
+ block->data,
+ target_state[fired_target_num].block_id,
+ true /*ack target data*/);
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to read last data on (%s)!", target_name(ctx->cpus[fired_target_num]));
+ } else {
+ if (ctx->cores_num > 1) {
+ /* ack target data on another CPU */
+ empty_target_num = fired_target_num ? 0 : 1;
+ res = ctx->hw->ctrl_reg_write(ctx->cpus[empty_target_num],
+ target_state[fired_target_num].block_id,
+ 0 /*all read*/,
+ true /*host connected*/,
+ false /*no host data*/);
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to ack data on target '%s' (%d)!",
+ target_name(ctx->cpus[empty_target_num]), res);
+ return res;
+ }
+ }
+ /* process data */
+ block->data_len = target_state[fired_target_num].data_len;
+ res = esp32_apptrace_handle_trace_block(ctx, block);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to process trace block %" PRId32 " bytes!",
+ block->data_len);
+ return res;
+ }
+ }
+ old_block_id = target_state[fired_target_num].block_id;
+ }
+ }
+ if (duration_measure(&wait_time) != 0) {
+ LOG_ERROR("Failed to start trace stop timeout measurement!");
+ return ERROR_FAIL;
+ }
+ const float stop_tmo = LOG_LEVEL_IS(LOG_LVL_DEBUG) ? 30.0 : 0.5;
+ if (duration_elapsed(&wait_time) >= stop_tmo) {
+ LOG_INFO("Stop waiting for the last data due to timeout.");
+ break;
+ }
+ }
+ return res;
+}
+
int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const char **argv, int argc)
{
static struct esp32_apptrace_cmd_ctx s_at_cmd_ctx;
@@ -1264,17 +1459,39 @@ int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const c
old_state = target->state;
if (strcmp(argv[0], "start") == 0) {
- res = esp32_apptrace_cmd_init(&s_at_cmd_ctx,
- cmd,
- mode,
- &argv[1],
- argc - 1);
- if (res != ERROR_OK) {
- command_print(cmd, "Failed to init cmd ctx (%d)!", res);
- return res;
+ if (is_sysview_mode(mode)) {
+ /* init cmd context */
+ res = esp32_sysview_cmd_init(&s_at_cmd_ctx,
+ cmd,
+ mode,
+ mode == ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE,
+ &argv[1],
+ argc - 1);
+ if (res != ERROR_OK) {
+ command_print(cmd, "Failed to init cmd ctx (%d)!", res);
+ return res;
+ }
+ cmd_data = s_at_cmd_ctx.cmd_priv;
+ if (cmd_data->skip_len != 0) {
+ s_at_cmd_ctx.running = 0;
+ esp32_sysview_cmd_cleanup(&s_at_cmd_ctx);
+ command_print(cmd, "Data skipping not supported!");
+ return ERROR_FAIL;
+ }
+ s_at_cmd_ctx.process_data = esp32_sysview_process_data;
+ } else {
+ res = esp32_apptrace_cmd_init(&s_at_cmd_ctx,
+ cmd,
+ mode,
+ &argv[1],
+ argc - 1);
+ if (res != ERROR_OK) {
+ command_print(cmd, "Failed to init cmd ctx (%d)!", res);
+ return res;
+ }
+ cmd_data = s_at_cmd_ctx.cmd_priv;
+ s_at_cmd_ctx.process_data = esp32_apptrace_process_data;
}
- cmd_data = s_at_cmd_ctx.cmd_priv;
- s_at_cmd_ctx.process_data = esp32_apptrace_process_data;
s_at_cmd_ctx.auto_clean = esp32_apptrace_cmd_stop;
if (cmd_data->wait4halt) {
res = esp32_apptrace_wait4halt(&s_at_cmd_ctx, target);
@@ -1288,6 +1505,17 @@ int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const c
command_print(cmd, "Failed to connect to targets (%d)!", res);
goto _on_start_error;
}
+ if (is_sysview_mode(mode)) {
+ /* start tracing */
+ res = esp32_sysview_start(&s_at_cmd_ctx);
+ if (res != ERROR_OK) {
+ esp32_apptrace_connect_targets(&s_at_cmd_ctx, false, old_state == TARGET_RUNNING);
+ s_at_cmd_ctx.running = 0;
+ esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx);
+ command_print(cmd, "sysview: Failed to start tracing!");
+ return res;
+ }
+ }
res = target_register_timer_callback(esp32_apptrace_poll,
cmd_data->poll_period,
TARGET_TIMER_TYPE_PERIODIC,
@@ -1309,6 +1537,10 @@ int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const c
esp32_apptrace_print_stats(&s_at_cmd_ctx);
return ERROR_OK;
} else if (strcmp(argv[0], "dump") == 0) {
+ if (is_sysview_mode(mode)) {
+ command_print(cmd, "Not supported!");
+ return ERROR_FAIL;
+ }
/* [dump outfile] - post-mortem dump without connection to targets */
res = esp32_apptrace_cmd_init(&s_at_cmd_ctx,
cmd,
@@ -1349,7 +1581,10 @@ int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const c
_on_start_error:
s_at_cmd_ctx.running = 0;
- esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx);
+ if (is_sysview_mode(mode))
+ esp32_sysview_cmd_cleanup(&s_at_cmd_ctx);
+ else
+ esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx);
return res;
}
@@ -1358,6 +1593,16 @@ COMMAND_HANDLER(esp32_cmd_apptrace)
return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_GEN, CMD_ARGV, CMD_ARGC);
}
+COMMAND_HANDLER(esp32_cmd_sysview)
+{
+ return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_SYSVIEW, CMD_ARGV, CMD_ARGC);
+}
+
+COMMAND_HANDLER(esp32_cmd_sysview_mcore)
+{
+ return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE, CMD_ARGV, CMD_ARGC);
+}
+
const struct command_registration esp32_apptrace_command_handlers[] = {
{
.name = "apptrace",
@@ -1366,7 +1611,25 @@ const struct command_registration esp32_apptrace_command_handlers[] = {
.help =
"App Tracing: application level trace control. Starts, stops or queries tracing process status.",
.usage =
- "[start <destination> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] | [stop] | [status] | [dump <destination>]",
+ "(start <destination> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status) | (dump <destination>)",
+ },
+ {
+ .name = "sysview",
+ .handler = esp32_cmd_sysview,
+ .mode = COMMAND_EXEC,
+ .help =
+ "App Tracing: SEGGER SystemView compatible trace control. Starts, stops or queries tracing process status.",
+ .usage =
+ "(start file://<outfile1> [file://<outfile2>] [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status)",
+ },
+ {
+ .name = "sysview_mcore",
+ .handler = esp32_cmd_sysview_mcore,
+ .mode = COMMAND_EXEC,
+ .help =
+ "App Tracing: Espressif multi-core SystemView trace control. Starts, stops or queries tracing process status.",
+ .usage =
+ "(start file://<outfile> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status)",
},
COMMAND_REGISTRATION_DONE
};
diff --git a/src/target/espressif/esp32_sysview.c b/src/target/espressif/esp32_sysview.c
new file mode 100644
index 0000000..2fe2157
--- /dev/null
+++ b/src/target/espressif/esp32_sysview.c
@@ -0,0 +1,554 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * ESP32 sysview tracing module *
+ * Copyright (C) 2020 Espressif Systems Ltd. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/log.h>
+#include "esp32_apptrace.h"
+#include "esp32_sysview.h"
+#include "segger_sysview.h"
+
+/* in SystemView mode core ID is passed in event ID field */
+#define ESP32_SYSVIEW_USER_BLOCK_CORE(_v_) (0) /* not used */
+#define ESP32_SYSVIEW_USER_BLOCK_LEN(_v_) (_v_)
+#define ESP32_SYSVIEW_USER_BLOCK_HDR_SZ 2
+
+struct esp_sysview_target2host_hdr {
+ uint8_t block_sz;
+ uint8_t wr_sz;
+};
+#define SYSVIEW_BLOCK_SIZE_OFFSET 0
+#define SYSVIEW_WR_SIZE_OFFSET 1
+
+static int esp_sysview_trace_header_write(struct esp32_apptrace_cmd_ctx *ctx, bool mcore_format);
+static int esp32_sysview_core_id_get(struct target *target, uint8_t *hdr_buf);
+static uint32_t esp32_sysview_usr_block_len_get(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len);
+
+int esp32_sysview_cmd_init(struct esp32_apptrace_cmd_ctx *cmd_ctx,
+ struct command_invocation *cmd,
+ int mode,
+ bool mcore_format,
+ const char **argv,
+ int argc)
+{
+ struct esp32_sysview_cmd_data *cmd_data;
+
+ if (argc < 1) {
+ command_print(cmd, "Not enough args! Need trace data destination!");
+ return ERROR_FAIL;
+ }
+
+ int res = esp32_apptrace_cmd_ctx_init(cmd_ctx, cmd, mode);
+ if (res != ERROR_OK)
+ return res;
+
+ int core_num = cmd_ctx->cores_num;
+
+ if (!mcore_format && argc < core_num) {
+ command_print(cmd, "Not enough args! Need %d trace data destinations!", core_num);
+ res = ERROR_FAIL;
+ goto on_error;
+ }
+
+ cmd_data = calloc(1, sizeof(*cmd_data));
+ if (!cmd_data) {
+ command_print(cmd, "No memory for command data!");
+ res = ERROR_FAIL;
+ goto on_error;
+ }
+ cmd_ctx->cmd_priv = cmd_data;
+ cmd_data->mcore_format = mcore_format;
+
+ /*outfile1 [outfile2] [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] */
+ int dests_num = esp32_apptrace_dest_init(cmd_data->data_dests, argv, !mcore_format ? core_num : 1);
+ if (!mcore_format && dests_num < core_num) {
+ command_print(cmd, "Not enough args! Need %d trace data destinations!", core_num);
+ free(cmd_data);
+ res = ERROR_FAIL;
+ goto on_error;
+ }
+ cmd_data->apptrace.max_len = UINT32_MAX;
+ cmd_data->apptrace.poll_period = 0 /*ms*/;
+ cmd_ctx->stop_tmo = -1.0; /* infinite */
+ if (argc > dests_num) {
+ /* parse remaining args */
+ esp32_apptrace_cmd_args_parse(cmd_ctx,
+ &cmd_data->apptrace,
+ &argv[dests_num],
+ argc - dests_num);
+ }
+ LOG_USER("App trace params: from %d cores, size %u bytes, stop_tmo %g s, "
+ "poll period %u ms, wait_rst %d, skip %u bytes",
+ cmd_ctx->cores_num,
+ cmd_data->apptrace.max_len,
+ cmd_ctx->stop_tmo,
+ cmd_data->apptrace.poll_period,
+ cmd_data->apptrace.wait4halt,
+ cmd_data->apptrace.skip_len);
+
+ cmd_ctx->trace_format.hdr_sz = ESP32_SYSVIEW_USER_BLOCK_HDR_SZ;
+ cmd_ctx->trace_format.core_id_get = esp32_sysview_core_id_get;
+ cmd_ctx->trace_format.usr_block_len_get = esp32_sysview_usr_block_len_get;
+
+ res = esp_sysview_trace_header_write(cmd_ctx, mcore_format);
+ if (res != ERROR_OK) {
+ command_print(cmd, "Failed to write trace header (%d)!", res);
+ esp32_apptrace_dest_cleanup(cmd_data->data_dests, core_num);
+ free(cmd_data);
+ return res;
+ }
+ return ERROR_OK;
+on_error:
+ cmd_ctx->running = 0;
+ esp32_apptrace_cmd_ctx_cleanup(cmd_ctx);
+ return res;
+}
+
+int esp32_sysview_cmd_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx)
+{
+ struct esp32_sysview_cmd_data *cmd_data = cmd_ctx->cmd_priv;
+
+ esp32_apptrace_dest_cleanup(cmd_data->data_dests, cmd_ctx->cores_num);
+ free(cmd_data);
+ cmd_ctx->cmd_priv = NULL;
+ esp32_apptrace_cmd_ctx_cleanup(cmd_ctx);
+ return ERROR_OK;
+}
+
+static int esp32_sysview_core_id_get(struct target *target, uint8_t *hdr_buf)
+{
+ /* for sysview compressed apptrace header is used, so core id is encoded in sysview packet */
+ return 0;
+}
+
+static uint32_t esp32_sysview_usr_block_len_get(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len)
+{
+ *wr_len = ESP32_SYSVIEW_USER_BLOCK_LEN(hdr_buf[SYSVIEW_WR_SIZE_OFFSET]);
+ return ESP32_SYSVIEW_USER_BLOCK_LEN(hdr_buf[SYSVIEW_BLOCK_SIZE_OFFSET]);
+}
+
+static int esp_sysview_trace_header_write(struct esp32_apptrace_cmd_ctx *ctx, bool mcore_format)
+{
+ struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
+ char *hdr_str;
+ int dests_num;
+
+ if (!mcore_format) {
+ hdr_str = ";\n"
+ "; Version " SYSVIEW_MIN_VER_STRING "\n"
+ "; Author Espressif Inc\n"
+ ";\n";
+ dests_num = ctx->cores_num;
+ } else {
+ hdr_str = ";\n"
+ "; Version " SYSVIEW_MIN_VER_STRING "\n"
+ "; Author Espressif Inc\n"
+ "; ESP_Extension\n"
+ ";\n";
+ dests_num = 1;
+ }
+
+ int hdr_len = strlen(hdr_str);
+ for (int i = 0; i < dests_num; i++) {
+ int res = cmd_data->data_dests[i].write(cmd_data->data_dests[i].priv,
+ (uint8_t *)hdr_str,
+ hdr_len);
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to write %u bytes to dest %d!", hdr_len, i);
+ return ERROR_FAIL;
+ }
+ }
+ return ERROR_OK;
+}
+
+static void sysview_encode_u32(uint8_t **dest, uint32_t val)
+{
+ uint8_t *sv_ptr = *dest;
+ while (val > 0x7F) {
+ *sv_ptr++ = (uint8_t)(val | 0x80);
+ val >>= 7;
+ }
+ *sv_ptr++ = (uint8_t)val;
+ *dest = sv_ptr;
+}
+
+static uint32_t esp_sysview_decode_u32(uint8_t **ptr)
+{
+ uint32_t val = 0;
+ for (int k = 0;; k++, (*ptr)++) {
+ if (**ptr & 0x80) {
+ val |= (uint32_t)(**ptr & ~0x80) << 7 * k;
+ } else {
+ val |= (uint32_t)**ptr << 7 * k;
+ (*ptr)++;
+ break;
+ }
+ }
+ return val;
+}
+
+static uint16_t esp_sysview_decode_plen(uint8_t **ptr)
+{
+ uint16_t payload_len = 0;
+ uint8_t *p = *ptr;
+ /* here pkt points to encoded payload length */
+ if (*p & 0x80) {
+ payload_len = *(p + 1); /* higher part */
+ payload_len = (payload_len << 7) | (*p & ~0x80);/* lower 7 bits */
+ p += 2; /* payload len (2 bytes) */
+ } else {
+ payload_len = *p;
+ p++; /* payload len (1 byte) */
+ }
+ *ptr = p;
+
+ return payload_len;
+}
+
+static uint16_t esp_sysview_get_predef_payload_len(uint16_t id, uint8_t *pkt)
+{
+ uint16_t len;
+ uint8_t *ptr = pkt;
+
+ switch (id) {
+ case SYSVIEW_EVTID_OVERFLOW:
+ case SYSVIEW_EVTID_ISR_ENTER:
+ case SYSVIEW_EVTID_TASK_START_EXEC:
+ case SYSVIEW_EVTID_TASK_START_READY:
+ case SYSVIEW_EVTID_TASK_CREATE:
+ case SYSVIEW_EVTID_SYSTIME_CYCLES:
+ case SYSVIEW_EVTID_USER_START:
+ case SYSVIEW_EVTID_USER_STOP:
+ case SYSVIEW_EVTID_TIMER_ENTER:
+ /*ENCODE_U32 */
+ esp_sysview_decode_u32(&ptr);
+ len = ptr - pkt;
+ break;
+ case SYSVIEW_EVTID_TASK_STOP_READY:
+ case SYSVIEW_EVTID_SYSTIME_US:
+ /*2*ENCODE_U32 */
+ esp_sysview_decode_u32(&ptr);
+ esp_sysview_decode_u32(&ptr);
+ len = ptr - pkt;
+ break;
+ case SYSVIEW_EVTID_SYSDESC:
+ /*str(128 + 1) */
+ len = *ptr + 1;
+ break;
+ case SYSVIEW_EVTID_TASK_INFO:
+ case SYSVIEW_EVTID_MODULEDESC:
+ /*2*ENCODE_U32 + str */
+ esp_sysview_decode_u32(&ptr);
+ esp_sysview_decode_u32(&ptr);
+ /* TODO: add support for strings longer then 255 bytes */
+ len = ptr - pkt + *ptr + 1;
+ break;
+ case SYSVIEW_EVTID_STACK_INFO:
+ /*4*ENCODE_U32 */
+ esp_sysview_decode_u32(&ptr);
+ esp_sysview_decode_u32(&ptr);
+ esp_sysview_decode_u32(&ptr);
+ esp_sysview_decode_u32(&ptr);
+ len = ptr - pkt;
+ break;
+ case SYSVIEW_EVTID_ISR_EXIT:
+ case SYSVIEW_EVTID_TASK_STOP_EXEC:
+ case SYSVIEW_EVTID_TRACE_START:
+ case SYSVIEW_EVTID_TRACE_STOP:
+ case SYSVIEW_EVTID_IDLE:
+ case SYSVIEW_EVTID_ISR_TO_SCHEDULER:
+ case SYSVIEW_EVTID_TIMER_EXIT:
+ len = 0;
+ break;
+
+ /*case SYSVIEW_EVTID_NOP: */
+ default:
+ LOG_ERROR("sysview: Unsupported predef event %d!", id);
+ len = 0;
+ }
+ return len;
+}
+
+static uint16_t esp_sysview_parse_packet(uint8_t *pkt_buf,
+ uint32_t *pkt_len,
+ unsigned int *pkt_core_id,
+ uint32_t *delta,
+ uint32_t *delta_len,
+ bool clear_core_bit)
+{
+ uint8_t *pkt = pkt_buf;
+ uint16_t event_id = 0, payload_len = 0;
+
+ *pkt_core_id = 0;
+ *pkt_len = 0;
+ /* 1-2 byte of message type, 0-2 byte of payload length, payload, 1-5 bytes of timestamp. */
+ if (*pkt & 0x80) {
+ if (*(pkt + 1) & (1 << 6)) {
+ if (clear_core_bit)
+ *(pkt + 1) &= ~(1 << 6); /* clear core_id bit */
+ *pkt_core_id = 1;
+ }
+ event_id = *(pkt + 1) & ~(1 << 6); /* higher part */
+ event_id = (event_id << 7) | (*pkt & ~0x80); /* lower 7 bits */
+ pkt += 2; /* event_id (2 bytes) */
+ /* here pkt points to encoded payload length */
+ payload_len = esp_sysview_decode_plen(&pkt);
+ } else {
+ if (*pkt & (1 << 6)) {
+ if (clear_core_bit)
+ *pkt &= ~(1 << 6); /* clear core_id bit */
+ *pkt_core_id = 1;
+ }
+ /* event_id (1 byte) */
+ event_id = *pkt & ~(1 << 6);
+ pkt++;
+ if (event_id < 24)
+ payload_len = esp_sysview_get_predef_payload_len(event_id, pkt);
+ else
+ payload_len = esp_sysview_decode_plen(&pkt);
+ }
+ pkt += payload_len;
+ uint8_t *delta_start = pkt;
+ *delta = esp_sysview_decode_u32(&pkt);
+ *delta_len = pkt - delta_start;
+ *pkt_len = pkt - pkt_buf;
+ LOG_DEBUG("sysview: evt %d len %d plen %d dlen %d",
+ event_id,
+ *pkt_len,
+ payload_len,
+ *delta_len);
+ return event_id;
+}
+
+static int esp32_sysview_write_packet(struct esp32_sysview_cmd_data *cmd_data,
+ int pkt_core_id, uint32_t pkt_len, uint8_t *pkt_buf, uint32_t delta_len, uint8_t *delta_buf)
+{
+ if (!cmd_data->data_dests[pkt_core_id].write)
+ return ERROR_FAIL;
+
+ int res = cmd_data->data_dests[pkt_core_id].write(cmd_data->data_dests[pkt_core_id].priv, pkt_buf, pkt_len);
+
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to write %u bytes to dest %d!", pkt_len, pkt_core_id);
+ return res;
+ }
+ if (delta_len) {
+ /* write packet with modified delta */
+ res = cmd_data->data_dests[pkt_core_id].write(cmd_data->data_dests[pkt_core_id].priv, delta_buf, delta_len);
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to write %u bytes of delta to dest %d!", delta_len, pkt_core_id);
+ return res;
+ }
+ }
+ return ERROR_OK;
+}
+
+static int esp32_sysview_process_packet(struct esp32_apptrace_cmd_ctx *ctx,
+ unsigned int pkt_core_id, uint16_t event_id, uint32_t delta, uint32_t delta_len,
+ uint32_t pkt_len, uint8_t *pkt_buf)
+{
+ struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
+ int pkt_core_changed = 0;
+ uint32_t new_delta_len = 0;
+ uint8_t new_delta_buf[10];
+ uint32_t wr_len = pkt_len;
+
+ if (ctx->cores_num > 1) {
+ if (cmd_data->sv_last_core_id == pkt_core_id) {
+ /* if this packet is for the same core as the prev one acc delta and write packet unmodified */
+ cmd_data->sv_acc_time_delta += delta;
+ } else {
+ /* if this packet is for another core then prev one set acc delta to the packet's delta */
+ uint8_t *delta_ptr = new_delta_buf;
+ sysview_encode_u32(&delta_ptr, delta + cmd_data->sv_acc_time_delta);
+ cmd_data->sv_acc_time_delta = delta;
+ wr_len -= delta_len;
+ new_delta_len = delta_ptr - new_delta_buf;
+ pkt_core_changed = 1;
+ }
+ cmd_data->sv_last_core_id = pkt_core_id;
+ }
+ if (pkt_core_id >= ctx->cores_num) {
+ LOG_WARNING("sysview: invalid core ID in packet %d, must be less then %d! Event id %d",
+ pkt_core_id,
+ ctx->cores_num,
+ event_id);
+ return ERROR_FAIL;
+ }
+ int res = esp32_sysview_write_packet(cmd_data,
+ pkt_core_id,
+ wr_len,
+ pkt_buf,
+ new_delta_len,
+ new_delta_buf);
+ if (res != ERROR_OK)
+ return res;
+ for (unsigned int i = 0; i < ctx->cores_num; i++) {
+ if (pkt_core_id == i)
+ continue;
+ switch (event_id) {
+ /* messages below should be sent to trace destinations for all cores */
+ case SYSVIEW_EVTID_TRACE_START:
+ case SYSVIEW_EVTID_TRACE_STOP:
+ case SYSVIEW_EVTID_SYSTIME_CYCLES:
+ case SYSVIEW_EVTID_SYSTIME_US:
+ case SYSVIEW_EVTID_SYSDESC:
+ case SYSVIEW_EVTID_TASK_INFO:
+ case SYSVIEW_EVTID_STACK_INFO:
+ case SYSVIEW_EVTID_MODULEDESC:
+ case SYSVIEW_EVTID_INIT:
+ case SYSVIEW_EVTID_NUMMODULES:
+ case SYSVIEW_EVTID_OVERFLOW:
+ case SYSVIEW_EVTID_TASK_START_READY:
+ /* if packet's source core has changed */
+ wr_len = pkt_len;
+ if (pkt_core_changed) {
+ /* clone packet with unmodified delta */
+ new_delta_len = 0;
+ } else {
+ /* clone packet with modified delta */
+ uint8_t *delta_ptr = new_delta_buf;
+ sysview_encode_u32(&delta_ptr, cmd_data->sv_acc_time_delta /*delta has been accumulated above*/);
+ wr_len -= delta_len;
+ new_delta_len = delta_ptr - new_delta_buf;
+ }
+ LOG_DEBUG("sysview: Redirect %d bytes of event %d to dest %d", wr_len, event_id, i);
+ res = esp32_sysview_write_packet(cmd_data,
+ i,
+ wr_len,
+ pkt_buf,
+ new_delta_len,
+ new_delta_buf);
+ if (res != ERROR_OK)
+ return res;
+ /* messages above are cloned to trace files for both cores,
+ * so reset acc time delta, both files have actual delta
+ * info */
+ cmd_data->sv_acc_time_delta = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ return ERROR_OK;
+}
+
+int esp32_sysview_process_data(struct esp32_apptrace_cmd_ctx *ctx,
+ unsigned int core_id,
+ uint8_t *data,
+ uint32_t data_len)
+{
+ struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
+
+ LOG_DEBUG("sysview: Read from target %d bytes [%x %x %x %x]",
+ data_len,
+ data[0],
+ data[1],
+ data[2],
+ data[3]);
+ int res;
+ uint32_t processed = 0;
+ if (core_id >= ctx->cores_num) {
+ LOG_ERROR("sysview: Invalid core id %d in user block!", core_id);
+ return ERROR_FAIL;
+ }
+ if (cmd_data->mcore_format)
+ core_id = 0;
+ if (ctx->tot_len == 0) {
+ /* handle sync seq */
+ if (data_len < SYSVIEW_SYNC_LEN) {
+ LOG_ERROR("sysview: Invalid init seq len %d!", data_len);
+ return ERROR_FAIL;
+ }
+ LOG_DEBUG("sysview: Process %d sync bytes", SYSVIEW_SYNC_LEN);
+ uint8_t sync_seq[SYSVIEW_SYNC_LEN] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
+ if (memcmp(data, sync_seq, SYSVIEW_SYNC_LEN) != 0) {
+ LOG_ERROR("sysview: Invalid init seq [%x %x %x %x %x %x %x %x %x %x]",
+ data[0], data[1], data[2], data[3], data[4], data[5], data[6],
+ data[7], data[8], data[9]);
+ return ERROR_FAIL;
+ }
+ res = cmd_data->data_dests[core_id].write(cmd_data->data_dests[core_id].priv,
+ data,
+ SYSVIEW_SYNC_LEN);
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to write %u sync bytes to dest %d!",
+ SYSVIEW_SYNC_LEN,
+ core_id);
+ return res;
+ }
+ if (!cmd_data->mcore_format) {
+ for (unsigned int i = 0; i < ctx->cores_num; i++) {
+ if (core_id == i)
+ continue;
+ res =
+ cmd_data->data_dests[i].write(cmd_data->data_dests[i].priv,
+ data,
+ SYSVIEW_SYNC_LEN);
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to write %u sync bytes to dest %d!", SYSVIEW_SYNC_LEN, core_id ? 0 : 1);
+ return res;
+ }
+ }
+ }
+ ctx->tot_len += SYSVIEW_SYNC_LEN;
+ processed += SYSVIEW_SYNC_LEN;
+ }
+ while (processed < data_len) {
+ unsigned int pkt_core_id;
+ uint32_t delta_len = 0;
+ uint32_t pkt_len = 0, delta = 0;
+ uint16_t event_id = esp_sysview_parse_packet(data + processed,
+ &pkt_len,
+ &pkt_core_id,
+ &delta,
+ &delta_len,
+ !cmd_data->mcore_format);
+ LOG_DEBUG("sysview: Process packet: core %d, %d id, %d bytes [%x %x %x %x]",
+ pkt_core_id,
+ event_id,
+ pkt_len,
+ data[processed + 0],
+ data[processed + 1],
+ data[processed + 2],
+ data[processed + 3]);
+ if (!cmd_data->mcore_format) {
+ res = esp32_sysview_process_packet(ctx,
+ pkt_core_id,
+ event_id,
+ delta,
+ delta_len,
+ pkt_len,
+ data + processed);
+ if (res != ERROR_OK)
+ return res;
+ } else {
+ res = cmd_data->data_dests[0].write(cmd_data->data_dests[0].priv, data + processed, pkt_len);
+ if (res != ERROR_OK) {
+ LOG_ERROR("sysview: Failed to write %u bytes to dest %d!", pkt_len, 0);
+ return res;
+ }
+ }
+ if (event_id == SYSVIEW_EVTID_TRACE_STOP)
+ cmd_data->sv_trace_running = 0;
+ ctx->tot_len += pkt_len;
+ processed += pkt_len;
+ }
+ LOG_USER("%u ", ctx->tot_len);
+ /* check for stop condition */
+ if (ctx->tot_len > cmd_data->apptrace.skip_len &&
+ (ctx->tot_len - cmd_data->apptrace.skip_len >= cmd_data->apptrace.max_len)) {
+ ctx->running = 0;
+ if (duration_measure(&ctx->read_time) != 0) {
+ LOG_ERROR("Failed to stop trace read time measure!");
+ return ERROR_FAIL;
+ }
+ }
+ return ERROR_OK;
+}
diff --git a/src/target/espressif/esp32_sysview.h b/src/target/espressif/esp32_sysview.h
new file mode 100644
index 0000000..230ce46
--- /dev/null
+++ b/src/target/espressif/esp32_sysview.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ * ESP32 sysview tracing module *
+ * Copyright (C) 2020 Espressif Systems Ltd. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ESP32_SYSVIEW_H
+#define OPENOCD_TARGET_ESP32_SYSVIEW_H
+
+#include <stdint.h>
+#include "esp32_apptrace.h"
+
+struct esp32_sysview_cmd_data {
+ /* Should be the first field. Generic apptrace command handling code accesses it */
+ struct esp32_apptrace_cmd_data apptrace;
+ struct esp32_apptrace_dest data_dests[ESP32_APPTRACE_MAX_CORES_NUM];
+ bool mcore_format;
+ uint32_t sv_acc_time_delta;
+ unsigned int sv_last_core_id;
+ int sv_trace_running;
+};
+
+struct esp32_apptrace_cmd_ctx;
+
+int esp32_sysview_cmd_init(struct esp32_apptrace_cmd_ctx *cmd_ctx,
+ struct command_invocation *cmd,
+ int mode,
+ bool mcore_format,
+ const char **argv,
+ int argc);
+int esp32_sysview_cmd_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx);
+int esp32_sysview_process_data(struct esp32_apptrace_cmd_ctx *ctx,
+ unsigned int core_id,
+ uint8_t *data,
+ uint32_t data_len);
+
+#endif /* OPENOCD_TARGET_ESP32_SYSVIEW_H */
diff --git a/src/target/espressif/segger_sysview.h b/src/target/espressif/segger_sysview.h
new file mode 100644
index 0000000..d149cab
--- /dev/null
+++ b/src/target/espressif/segger_sysview.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: BSD-1-Clause */
+/* SPDX-FileCopyrightText: (c) 1995-2021 SEGGER Microcontroller GmbH. All rights reserved. */
+/* SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD */
+
+/*
+* The contend below is extracted from files SEGGER_SYSVIEW.h and SEGGER_SYSVIEW_Int.h in:
+* https://www.segger.com/downloads/systemview/systemview_target_src
+* SystemView version: 3.42
+*/
+
+#ifndef OPENOCD_TARGET_SEGGER_SYSVIEW_H
+#define OPENOCD_TARGET_SEGGER_SYSVIEW_H
+
+#define SYSVIEW_EVTID_NOP 0 /* Dummy packet. */
+#define SYSVIEW_EVTID_OVERFLOW 1
+#define SYSVIEW_EVTID_ISR_ENTER 2
+#define SYSVIEW_EVTID_ISR_EXIT 3
+#define SYSVIEW_EVTID_TASK_START_EXEC 4
+#define SYSVIEW_EVTID_TASK_STOP_EXEC 5
+#define SYSVIEW_EVTID_TASK_START_READY 6
+#define SYSVIEW_EVTID_TASK_STOP_READY 7
+#define SYSVIEW_EVTID_TASK_CREATE 8
+#define SYSVIEW_EVTID_TASK_INFO 9
+#define SYSVIEW_EVTID_TRACE_START 10
+#define SYSVIEW_EVTID_TRACE_STOP 11
+#define SYSVIEW_EVTID_SYSTIME_CYCLES 12
+#define SYSVIEW_EVTID_SYSTIME_US 13
+#define SYSVIEW_EVTID_SYSDESC 14
+#define SYSVIEW_EVTID_USER_START 15
+#define SYSVIEW_EVTID_USER_STOP 16
+#define SYSVIEW_EVTID_IDLE 17
+#define SYSVIEW_EVTID_ISR_TO_SCHEDULER 18
+#define SYSVIEW_EVTID_TIMER_ENTER 19
+#define SYSVIEW_EVTID_TIMER_EXIT 20
+#define SYSVIEW_EVTID_STACK_INFO 21
+#define SYSVIEW_EVTID_MODULEDESC 22
+
+#define SYSVIEW_EVTID_INIT 24
+#define SYSVIEW_EVTID_NAME_RESOURCE 25
+#define SYSVIEW_EVTID_PRINT_FORMATTED 26
+#define SYSVIEW_EVTID_NUMMODULES 27
+#define SYSVIEW_EVTID_END_CALL 28
+#define SYSVIEW_EVTID_TASK_TERMINATE 29
+
+#define SYSVIEW_EVTID_EX 31
+//
+// SystemView extended events. Sent with ID 31.
+//
+#define SYSVIEW_EVTID_EX_MARK 0
+#define SYSVIEW_EVTID_EX_NAME_MARKER 1
+#define SYSVIEW_EVTID_EX_HEAP_DEFINE 2
+#define SYSVIEW_EVTID_EX_HEAP_ALLOC 3
+#define SYSVIEW_EVTID_EX_HEAP_ALLOC_EX 4
+#define SYSVIEW_EVTID_EX_HEAP_FREE 5
+
+#define SYSVIEW_SYNC_LEN 10
+
+#define SYSVIEW_EVENT_ID_MAX (200)
+
+//
+// Commands that Host can send to target
+//
+enum {
+ SEGGER_SYSVIEW_COMMAND_ID_START = 1,
+ SEGGER_SYSVIEW_COMMAND_ID_STOP,
+ SEGGER_SYSVIEW_COMMAND_ID_GET_SYSTIME,
+ SEGGER_SYSVIEW_COMMAND_ID_GET_TASKLIST,
+ SEGGER_SYSVIEW_COMMAND_ID_GET_SYSDESC,
+ SEGGER_SYSVIEW_COMMAND_ID_GET_NUMMODULES,
+ SEGGER_SYSVIEW_COMMAND_ID_GET_MODULEDESC,
+ SEGGER_SYSVIEW_COMMAND_ID_HEARTBEAT = 127,
+ // Extended commands: Commands >= 128 have a second parameter
+ SEGGER_SYSVIEW_COMMAND_ID_GET_MODULE = 128
+};
+
+/* Minimum compatible SEGGER SystemView tool version */
+#define SYSVIEW_MIN_VER_STRING "SEGGER SystemViewer V2.42"
+
+#endif