This is an automated email from Gerrit. "Grant Ramsay <grant.ram...@hotmail.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8343
-- gerrit commit f9e5584fb3fc93e47542f83bafb71ec08e7e8175 Author: Grant Ramsay <grant.ram...@hotmail.com> Date: Sun Jun 16 20:27:11 2024 +1200 rtt: Add support for multiple RTT control block instances This is useful when a device has multiple RTT control blocks, probably on multiple AMP cores. A new command "rtt select_instance <instance_id>" allows creating/selecting the RTT instance to be used by other RTT commands. Change-Id: If02ebb2ca7075198a32bec6acae35840147ec86b Signed-off-by: Grant Ramsay <grant.ram...@hotmail.com> diff --git a/doc/openocd.texi b/doc/openocd.texi index e46e6004bc..c9cfcdde85 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -9482,10 +9482,6 @@ This interface is especially of interest for targets without Serial Wire Output (SWO), such as ARM Cortex-M0, or where semihosting is not applicable because of real-time constraints. -@quotation Note -The current implementation supports only single target devices. -@end quotation - The data transfer between host and target device is organized through unidirectional up/down-channels for target-to-host and host-to-target communication, respectively. @@ -9541,6 +9537,14 @@ Start a TCP server on @var{port} for the channel @var{channel}. When Stop the TCP sever with port @var{port}. @end deffn +@deffn {Command} {rtt select_instance} instance_id +Select the active RTT instance (not to be confused with RTT channels). +@var{instance_id} is an integer handle to the active RTT instance. +Other RTT commands will use the currently selected RTT instance. +This is useful when a device has multiple RTT control blocks, probably +on multiple AMP cores. The initial selected instance is 0. +@end deffn + The following example shows how to setup RTT using the SEGGER RTT implementation on the target device. @@ -9557,6 +9561,18 @@ In this example, OpenOCD searches the control block with the ID "SEGGER RTT" starting at 0x20000000 for 2048 bytes. The RTT channel 0 is exposed through the TCP/IP port 9090. +The following example adds a second RTT instance, seaching for another control +block at 0x21000000 for 2048 bytes. This instances RTT channel 0 is exposed +through the TCP/IP port 9091. + +@example +rtt select_instance 1 + +rtt setup 0x21000000 2048 "SEGGER RTT1" +rtt start + +rtt server start 9091 0 +@end example @section Misc Commands diff --git a/src/rtt/rtt.c b/src/rtt/rtt.c index e31e75410d..dd3bd9b313 100644 --- a/src/rtt/rtt.c +++ b/src/rtt/rtt.c @@ -2,6 +2,7 @@ /* * Copyright (C) 2016-2020 by Marc Schink <d...@zapb.de> + * Copyright (C) 2024 Grant Ramsay <grant.ram...@hotmail.com> */ #ifdef HAVE_CONFIG_H @@ -19,7 +20,7 @@ #include "rtt.h" -static struct { +struct rtt { struct rtt_source source; /** Control block. */ struct rtt_control ctrl; @@ -43,49 +44,116 @@ static struct { size_t sink_list_length; unsigned int polling_interval; -} rtt; -int rtt_init(void) + unsigned int instance_id; + struct list_head lh; +}; + +/** A list of all created RTT instances (used for cleanup). */ +static LIST_HEAD(rtt_list); + +/** The currently selected RTT instance. */ +static struct rtt *selected_instance; + +static struct rtt *rtt_new(int instance_id) { - rtt.sink_list_length = 1; - rtt.sink_list = calloc(rtt.sink_list_length, + struct rtt *rtt = calloc(1, sizeof(*rtt)); + if (!rtt) + return NULL; + + rtt->sink_list_length = 1; + rtt->sink_list = calloc(rtt->sink_list_length, sizeof(struct rtt_sink_list *)); - if (!rtt.sink_list) - return ERROR_FAIL; + if (!rtt->sink_list) + return NULL; - rtt.sink_list[0] = NULL; - rtt.started = false; + rtt->sink_list[0] = NULL; + rtt->started = false; - rtt.polling_interval = 100; + rtt->polling_interval = 100; - return ERROR_OK; + rtt->instance_id = instance_id; + list_add_tail(&rtt->lh, &rtt_list); + + return rtt; +} + +static void rtt_free(struct rtt *rtt) +{ + list_del(&rtt->lh); + free(rtt->sink_list); + free(rtt); +} + +static struct rtt *rtt_instance_by_id(unsigned int instance_id) +{ + struct rtt *rtt; + + list_for_each_entry(rtt, &rtt_list, lh) { + if (rtt->instance_id == instance_id) + return rtt; + } + + return NULL; +} + +int rtt_init(void) +{ + /* Create and select instance 0 */ + return rtt_select_instance(0); } int rtt_exit(void) { - free(rtt.sink_list); + struct rtt *rtt, *tmp; + + list_for_each_entry_safe(rtt, tmp, &rtt_list, lh) { + rtt_free(rtt); + } return ERROR_OK; } +int rtt_select_instance(unsigned int instance_id) +{ + struct rtt *rtt = rtt_instance_by_id(instance_id); + + /* Create a new instance if it does not exist */ + if (!rtt) { + rtt = rtt_new(instance_id); + if (!rtt) + return ERROR_FAIL; + } + + selected_instance = rtt; + + return ERROR_OK; +} + +struct rtt *rtt_get_selected_instance(void) +{ + return selected_instance; +} + static int read_channel_callback(void *user_data) { int ret; + struct rtt *rtt = user_data; - ret = rtt.source.read(rtt.target, &rtt.ctrl, rtt.sink_list, - rtt.sink_list_length, NULL); + ret = rtt->source.read(rtt->target, &rtt->ctrl, rtt->sink_list, + rtt->sink_list_length, NULL); if (ret != ERROR_OK) { - target_unregister_timer_callback(&read_channel_callback, NULL); - rtt.source.stop(rtt.target, NULL); + target_unregister_timer_callback(&read_channel_callback, rtt); + rtt->source.stop(rtt->target, NULL); return ret; } return ERROR_OK; } -int rtt_setup(target_addr_t address, size_t size, const char *id) +int rtt_setup(struct rtt *rtt, target_addr_t address, size_t size, const char *id) { size_t id_length = strlen(id); @@ -94,16 +162,16 @@ int rtt_setup(target_addr_t address, size_t size, const char *id) return ERROR_COMMAND_ARGUMENT_INVALID; } - rtt.addr = address; - rtt.size = size; - strncpy(rtt.id, id, id_length + 1); - rtt.changed = true; - rtt.configured = true; + rtt->addr = address; + rtt->size = size; + strncpy(rtt->id, id, id_length + 1); + rtt->changed = true; + rtt->configured = true; return ERROR_OK; } -int rtt_register_source(const struct rtt_source source, +int rtt_register_source(struct rtt *rtt, const struct rtt_source source, struct target *target) { if (!source.find_cb || !source.read_cb || !source.read_channel_info) @@ -115,66 +183,66 @@ int rtt_register_source(const struct rtt_source source, if (!source.read || !source.write) return ERROR_FAIL; - rtt.source = source; - rtt.target = target; + rtt->source = source; + rtt->target = target; return ERROR_OK; } -int rtt_start(void) +int rtt_start(struct rtt *rtt) { int ret; - target_addr_t addr = rtt.addr; + target_addr_t addr = rtt->addr; - if (rtt.started) + if (rtt->started) return ERROR_OK; - if (!rtt.found_cb || rtt.changed) { - rtt.source.find_cb(rtt.target, &addr, rtt.size, rtt.id, - &rtt.found_cb, NULL); + if (!rtt->found_cb || rtt->changed) { + rtt->source.find_cb(rtt->target, &addr, rtt->size, rtt->id, + &rtt->found_cb, NULL); - rtt.changed = false; + rtt->changed = false; - if (rtt.found_cb) { + if (rtt->found_cb) { LOG_INFO("rtt: Control block found at 0x%" TARGET_PRIxADDR, addr); - rtt.ctrl.address = addr; + rtt->ctrl.address = addr; } else { LOG_INFO("rtt: No control block found"); return ERROR_OK; } } - ret = rtt.source.read_cb(rtt.target, rtt.ctrl.address, &rtt.ctrl, NULL); + ret = rtt->source.read_cb(rtt->target, rtt->ctrl.address, &rtt->ctrl, NULL); if (ret != ERROR_OK) return ret; - ret = rtt.source.start(rtt.target, &rtt.ctrl, NULL); + ret = rtt->source.start(rtt->target, &rtt->ctrl, NULL); if (ret != ERROR_OK) return ret; target_register_timer_callback(&read_channel_callback, - rtt.polling_interval, 1, NULL); - rtt.started = true; + rtt->polling_interval, 1, rtt); + rtt->started = true; return ERROR_OK; } -int rtt_stop(void) +int rtt_stop(struct rtt *rtt) { int ret; - if (!rtt.configured) { + if (!rtt->configured) { LOG_ERROR("rtt: Not configured"); return ERROR_FAIL; } - target_unregister_timer_callback(&read_channel_callback, NULL); - rtt.started = false; + target_unregister_timer_callback(&read_channel_callback, rtt); + rtt->started = false; - ret = rtt.source.stop(rtt.target, NULL); + ret = rtt->source.stop(rtt->target, NULL); if (ret != ERROR_OK) return ret; @@ -182,34 +250,34 @@ int rtt_stop(void) return ERROR_OK; } -static int adjust_sink_list(size_t length) +static int adjust_sink_list(struct rtt *rtt, size_t length) { struct rtt_sink_list **tmp; - if (length <= rtt.sink_list_length) + if (length <= rtt->sink_list_length) return ERROR_OK; - tmp = realloc(rtt.sink_list, sizeof(struct rtt_sink_list *) * length); + tmp = realloc(rtt->sink_list, sizeof(struct rtt_sink_list *) * length); if (!tmp) return ERROR_FAIL; - for (size_t i = rtt.sink_list_length; i < length; i++) + for (size_t i = rtt->sink_list_length; i < length; i++) tmp[i] = NULL; - rtt.sink_list = tmp; - rtt.sink_list_length = length; + rtt->sink_list = tmp; + rtt->sink_list_length = length; return ERROR_OK; } -int rtt_register_sink(unsigned int channel_index, rtt_sink_read read, +int rtt_register_sink(struct rtt *rtt, unsigned int channel_index, rtt_sink_read read, void *user_data) { struct rtt_sink_list *tmp; - if (channel_index >= rtt.sink_list_length) { - if (adjust_sink_list(channel_index + 1) != ERROR_OK) + if (channel_index >= rtt->sink_list_length) { + if (adjust_sink_list(rtt, channel_index + 1) != ERROR_OK) return ERROR_FAIL; } @@ -222,31 +290,31 @@ int rtt_register_sink(unsigned int channel_index, rtt_sink_read read, tmp->read = read; tmp->user_data = user_data; - tmp->next = rtt.sink_list[channel_index]; + tmp->next = rtt->sink_list[channel_index]; - rtt.sink_list[channel_index] = tmp; + rtt->sink_list[channel_index] = tmp; return ERROR_OK; } -int rtt_unregister_sink(unsigned int channel_index, rtt_sink_read read, +int rtt_unregister_sink(struct rtt *rtt, unsigned int channel_index, rtt_sink_read read, void *user_data) { struct rtt_sink_list *prev_sink; LOG_DEBUG("rtt: Unregistering sink for channel %u", channel_index); - if (channel_index >= rtt.sink_list_length) + if (channel_index >= rtt->sink_list_length) return ERROR_FAIL; - prev_sink = rtt.sink_list[channel_index]; + prev_sink = rtt->sink_list[channel_index]; - for (struct rtt_sink_list *sink = rtt.sink_list[channel_index]; sink; + for (struct rtt_sink_list *sink = rtt->sink_list[channel_index]; sink; prev_sink = sink, sink = sink->next) { if (sink->read == read && sink->user_data == user_data) { - if (sink == rtt.sink_list[channel_index]) - rtt.sink_list[channel_index] = sink->next; + if (sink == rtt->sink_list[channel_index]) + rtt->sink_list[channel_index] = sink->next; else prev_sink->next = sink->next; @@ -259,67 +327,67 @@ int rtt_unregister_sink(unsigned int channel_index, rtt_sink_read read, return ERROR_OK; } -int rtt_get_polling_interval(unsigned int *interval) +int rtt_get_polling_interval(struct rtt *rtt, unsigned int *interval) { if (!interval) return ERROR_FAIL; - *interval = rtt.polling_interval; + *interval = rtt->polling_interval; return ERROR_OK; } -int rtt_set_polling_interval(unsigned int interval) +int rtt_set_polling_interval(struct rtt *rtt, unsigned int interval) { if (!interval) return ERROR_FAIL; - if (rtt.polling_interval != interval) { - target_unregister_timer_callback(&read_channel_callback, NULL); + if (rtt->polling_interval != interval) { + target_unregister_timer_callback(&read_channel_callback, rtt); target_register_timer_callback(&read_channel_callback, interval, 1, - NULL); + rtt); } - rtt.polling_interval = interval; + rtt->polling_interval = interval; return ERROR_OK; } -int rtt_write_channel(unsigned int channel_index, const uint8_t *buffer, +int rtt_write_channel(struct rtt *rtt, unsigned int channel_index, const uint8_t *buffer, size_t *length) { - if (channel_index >= rtt.ctrl.num_up_channels) { + if (channel_index >= rtt->ctrl.num_up_channels) { LOG_WARNING("rtt: Down-channel %u is not available", channel_index); return ERROR_OK; } - return rtt.source.write(rtt.target, &rtt.ctrl, channel_index, buffer, + return rtt->source.write(rtt->target, &rtt->ctrl, channel_index, buffer, length, NULL); } -bool rtt_started(void) +bool rtt_started(struct rtt *rtt) { - return rtt.started; + return rtt->started; } -bool rtt_configured(void) +bool rtt_configured(struct rtt *rtt) { - return rtt.configured; + return rtt->configured; } -bool rtt_found_cb(void) +bool rtt_found_cb(struct rtt *rtt) { - return rtt.found_cb; + return rtt->found_cb; } -const struct rtt_control *rtt_get_control(void) +const struct rtt_control *rtt_get_control(struct rtt *rtt) { - return &rtt.ctrl; + return &rtt->ctrl; } -int rtt_read_channel_info(unsigned int channel_index, +int rtt_read_channel_info(struct rtt *rtt, unsigned int channel_index, enum rtt_channel_type type, struct rtt_channel_info *info) { - return rtt.source.read_channel_info(rtt.target, &rtt.ctrl, + return rtt->source.read_channel_info(rtt->target, &rtt->ctrl, channel_index, type, info, NULL); } diff --git a/src/rtt/rtt.h b/src/rtt/rtt.h index a5630a9515..9f544e68c9 100644 --- a/src/rtt/rtt.h +++ b/src/rtt/rtt.h @@ -27,6 +27,9 @@ /* Minimal channel buffer size in bytes. */ #define RTT_CHANNEL_BUFFER_MIN_SIZE 2 +/** Forward declaration of opaque RTT instance */ +struct rtt; + /** RTT control block. */ struct rtt_control { /** Control block address on the target. */ @@ -128,6 +131,7 @@ struct rtt_source { /** * Initialize Real-Time Transfer (RTT). + * Creates and selects instance 0. * * @returns ERROR_OK on success, an error code on failure. */ @@ -140,127 +144,165 @@ int rtt_init(void); */ int rtt_exit(void); +/** + * Select which RTT instance will be returned by rtt_get_selected_instance(). + * If the instance does not exist it will be created. + * Useful for multicore devices that have multiple RTT control blocks. + * + * @param[in] instance_id The ID of the RTT instance to select. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_select_instance(unsigned int instance_id); + +/** + * Get the currently selected RTT instance. + * + * @returns a pointer to the currently selected RTT instance. + */ +struct rtt *rtt_get_selected_instance(void); + /** * Register an RTT source for a target. * + * @param[in] rtt RTT instance. * @param[in] source RTT source. * @param[in,out] target Target. * * @returns ERROR_OK on success, an error code on failure. */ -int rtt_register_source(const struct rtt_source source, +int rtt_register_source(struct rtt *rtt, const struct rtt_source source, struct target *target); /** * Setup RTT. * + * @param[in] rtt RTT instance. * @param[in] address Start address to search for the control block. * @param[in] size Size of the control block search area. * @param[in] id Identifier of the control block. Must be null-terminated. * * @returns ERROR_OK on success, an error code on failure. */ -int rtt_setup(target_addr_t address, size_t size, const char *id); +int rtt_setup(struct rtt *rtt, target_addr_t address, size_t size, const char *id); /** * Start Real-Time Transfer (RTT). * + * @param[in] rtt RTT instance. + * * @returns ERROR_OK on success, an error code on failure. */ -int rtt_start(void); +int rtt_start(struct rtt *rtt); /** * Stop Real-Time Transfer (RTT). * + * @param[in] rtt RTT instance. + * * @returns ERROR_OK on success, an error code on failure. */ -int rtt_stop(void); +int rtt_stop(struct rtt *rtt); /** * Get the polling interval. * + * @param[in] rtt RTT instance. * @param[out] interval Polling interval in milliseconds. * * @returns ERROR_OK on success, an error code on failure. */ -int rtt_get_polling_interval(unsigned int *interval); +int rtt_get_polling_interval(struct rtt *rtt, unsigned int *interval); /** * Set the polling interval. * + * @param[in] rtt RTT instance. * @param[in] interval Polling interval in milliseconds. * * @returns ERROR_OK on success, an error code on failure. */ -int rtt_set_polling_interval(unsigned int interval); +int rtt_set_polling_interval(struct rtt *rtt, unsigned int interval); /** * Get whether RTT is started. * + * @param[in] rtt RTT instance. + * * @returns Whether RTT is started. */ -bool rtt_started(void); +bool rtt_started(struct rtt *rtt); /** * Get whether RTT is configured. * + * @param[in] rtt RTT instance. + * * @returns Whether RTT is configured. */ -bool rtt_configured(void); +bool rtt_configured(struct rtt *rtt); /** * Get whether RTT control block was found. * + * @param[in] rtt RTT instance. + * * @returns Whether RTT was found. */ -bool rtt_found_cb(void); +bool rtt_found_cb(struct rtt *rtt); /** * Get the RTT control block. * + * @param[in] rtt RTT instance. + * * @returns The RTT control block. */ -const struct rtt_control *rtt_get_control(void); +const struct rtt_control *rtt_get_control(struct rtt *rtt); /** * Read channel information. * + * @param[in] rtt RTT instance. * @param[in] channel_index Channel index. * @param[in] type Channel type. * @param[out] info Channel information. * * @returns ERROR_OK on success, an error code on failure. */ -int rtt_read_channel_info(unsigned int channel_index, +int rtt_read_channel_info(struct rtt *rtt, unsigned int channel_index, enum rtt_channel_type type, struct rtt_channel_info *info); /** * Register an RTT sink. * + * @param[in] rtt RTT instance. * @param[in] channel_index Channel index. * @param[in] read Read callback function. * @param[in,out] user_data User data to be passed to the callback function. * * @returns ERROR_OK on success, an error code on failure. */ -int rtt_register_sink(unsigned int channel_index, rtt_sink_read read, +int rtt_register_sink(struct rtt *rtt, unsigned int channel_index, rtt_sink_read read, void *user_data); /** * Unregister an RTT sink. * + * @param[in] rtt RTT instance. * @param[in] channel_index Channel index. * @param[in] read Read callback function. * @param[in,out] user_data User data to be passed to the callback function. * * @returns ERROR_OK on success, an error code on failure. */ -int rtt_unregister_sink(unsigned int channel_index, rtt_sink_read read, +int rtt_unregister_sink(struct rtt *rtt, unsigned int channel_index, rtt_sink_read read, void *user_data); /** * Write to an RTT channel. * + * @param[in] rtt RTT instance. * @param[in] channel_index Channel index. * @param[in] buffer Buffer with data that should be written to the channel. * @param[in,out] length Number of bytes to write. On success, the argument gets @@ -268,7 +310,7 @@ int rtt_unregister_sink(unsigned int channel_index, rtt_sink_read read, * * @returns ERROR_OK on success, an error code on failure. */ -int rtt_write_channel(unsigned int channel_index, const uint8_t *buffer, +int rtt_write_channel(struct rtt *rtt, unsigned int channel_index, const uint8_t *buffer, size_t *length); extern const struct command_registration rtt_target_command_handlers[]; diff --git a/src/rtt/tcl.c b/src/rtt/tcl.c index 2b8822fce8..d328c1b3d3 100644 --- a/src/rtt/tcl.c +++ b/src/rtt/tcl.c @@ -2,6 +2,7 @@ /* * Copyright (C) 2019-2020 by Marc Schink <d...@zapb.de> + * Copyright (C) 2024 Grant Ramsay <grant.ram...@hotmail.com> */ #ifdef HAVE_CONFIG_H @@ -36,9 +37,14 @@ COMMAND_HANDLER(handle_rtt_setup_command) COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[0], address); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size); - rtt_register_source(source, get_current_target(CMD_CTX)); + struct rtt *rtt = rtt_get_selected_instance(); + if (!rtt) + return ERROR_FAIL; + + if (rtt_register_source(rtt, source, get_current_target(CMD_CTX)) != ERROR_OK) + return ERROR_FAIL; - if (rtt_setup(address, size, CMD_ARGV[2]) != ERROR_OK) + if (rtt_setup(rtt, address, size, CMD_ARGV[2]) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; @@ -49,12 +55,16 @@ COMMAND_HANDLER(handle_rtt_start_command) if (CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; - if (!rtt_configured()) { + struct rtt *rtt = rtt_get_selected_instance(); + if (!rtt) + return ERROR_FAIL; + + if (!rtt_configured(rtt)) { command_print(CMD, "RTT is not configured"); return ERROR_FAIL; } - return rtt_start(); + return rtt_start(rtt); } COMMAND_HANDLER(handle_rtt_stop_command) @@ -62,16 +72,24 @@ COMMAND_HANDLER(handle_rtt_stop_command) if (CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; - return rtt_stop(); + struct rtt *rtt = rtt_get_selected_instance(); + if (!rtt) + return ERROR_FAIL; + + return rtt_stop(rtt); } COMMAND_HANDLER(handle_rtt_polling_interval_command) { + struct rtt *rtt = rtt_get_selected_instance(); + if (!rtt) + return ERROR_FAIL; + if (CMD_ARGC == 0) { int ret; unsigned int interval; - ret = rtt_get_polling_interval(&interval); + ret = rtt_get_polling_interval(rtt, &interval); if (ret != ERROR_OK) { command_print(CMD, "Failed to get polling interval"); @@ -84,7 +102,7 @@ COMMAND_HANDLER(handle_rtt_polling_interval_command) unsigned int interval; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], interval); - ret = rtt_set_polling_interval(interval); + ret = rtt_set_polling_interval(rtt, interval); if (ret != ERROR_OK) { command_print(CMD, "Failed to set polling interval"); @@ -104,12 +122,16 @@ COMMAND_HANDLER(handle_rtt_channels_command) const struct rtt_control *ctrl; struct rtt_channel_info info; - if (!rtt_found_cb()) { + struct rtt *rtt = rtt_get_selected_instance(); + if (!rtt) + return ERROR_FAIL; + + if (!rtt_found_cb(rtt)) { command_print(CMD, "rtt: Control block not available"); return ERROR_FAIL; } - ctrl = rtt_get_control(); + ctrl = rtt_get_control(rtt); command_print(CMD, "Channels: up=%u, down=%u", ctrl->num_up_channels, ctrl->num_down_channels); @@ -120,7 +142,7 @@ COMMAND_HANDLER(handle_rtt_channels_command) info.name_length = sizeof(channel_name); for (unsigned int i = 0; i < ctrl->num_up_channels; i++) { - ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info); + ret = rtt_read_channel_info(rtt, i, RTT_CHANNEL_TYPE_UP, &info); if (ret != ERROR_OK) return ret; @@ -135,7 +157,7 @@ COMMAND_HANDLER(handle_rtt_channels_command) command_print(CMD, "Down-channels:"); for (unsigned int i = 0; i < ctrl->num_down_channels; i++) { - ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info); + ret = rtt_read_channel_info(rtt, i, RTT_CHANNEL_TYPE_DOWN, &info); if (ret != ERROR_OK) return ret; @@ -159,12 +181,16 @@ COMMAND_HANDLER(handle_channel_list) if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; - if (!rtt_found_cb()) { + struct rtt *rtt = rtt_get_selected_instance(); + if (!rtt) + return ERROR_FAIL; + + if (!rtt_found_cb(rtt)) { command_print(CMD, "rtt: Control block not available"); return ERROR_FAIL; } - ctrl = rtt_get_control(); + ctrl = rtt_get_control(rtt); info.name = channel_name; info.name_length = sizeof(channel_name); @@ -172,7 +198,7 @@ COMMAND_HANDLER(handle_channel_list) command_print(CMD, "{"); for (unsigned int i = 0; i < ctrl->num_up_channels; i++) { - int ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info); + int ret = rtt_read_channel_info(rtt, i, RTT_CHANNEL_TYPE_UP, &info); if (ret != ERROR_OK) return ret; @@ -191,7 +217,7 @@ COMMAND_HANDLER(handle_channel_list) command_print(CMD, "}\n{"); for (unsigned int i = 0; i < ctrl->num_down_channels; i++) { - int ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info); + int ret = rtt_read_channel_info(rtt, i, RTT_CHANNEL_TYPE_DOWN, &info); if (ret != ERROR_OK) return ret; @@ -212,6 +238,18 @@ COMMAND_HANDLER(handle_channel_list) return ERROR_OK; } +COMMAND_HANDLER(handle_rtt_select_instance) +{ + unsigned int instance_id; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], instance_id); + + return rtt_select_instance(instance_id); +} + static const struct command_registration rtt_subcommand_handlers[] = { { .name = "setup", @@ -255,6 +293,13 @@ static const struct command_registration rtt_subcommand_handlers[] = { .help = "list available channels", .usage = "" }, + { + .name = "select_instance", + .handler = handle_rtt_select_instance, + .mode = COMMAND_ANY, + .help = "select RTT instance", + .usage = "<instance_id>" + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/server/rtt_server.c b/src/server/rtt_server.c index 9769153475..25816e1b04 100644 --- a/src/server/rtt_server.c +++ b/src/server/rtt_server.c @@ -24,6 +24,7 @@ */ struct rtt_service { + struct rtt *rtt; unsigned int channel; char *hello_message; }; @@ -61,7 +62,7 @@ static int rtt_new_connection(struct connection *connection) LOG_DEBUG("rtt: New connection for channel %u", service->channel); - ret = rtt_register_sink(service->channel, &read_callback, connection); + ret = rtt_register_sink(service->rtt, service->channel, &read_callback, connection); if (ret != ERROR_OK) return ret; @@ -77,7 +78,7 @@ static int rtt_connection_closed(struct connection *connection) struct rtt_service *service; service = (struct rtt_service *)connection->service->priv; - rtt_unregister_sink(service->channel, &read_callback, connection); + rtt_unregister_sink(service->rtt, service->channel, &read_callback, connection); LOG_DEBUG("rtt: Connection for channel %u closed", service->channel); @@ -102,7 +103,7 @@ static int rtt_input(struct connection *connection) } length = bytes_read; - rtt_write_channel(service->channel, buffer, &length); + rtt_write_channel(service->rtt, service->channel, buffer, &length); return ERROR_OK; } @@ -129,6 +130,12 @@ COMMAND_HANDLER(handle_rtt_start_command) if (!service) return ERROR_FAIL; + service->rtt = rtt_get_selected_instance(); + if (!service->rtt) { + free(service); + return ERROR_FAIL; + } + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], service->channel); if (CMD_ARGC >= 3) { --