2 * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include <helper/log.h>
27 #include <helper/list.h>
28 #include <target/target.h>
29 #include <target/rtt.h>
34 struct rtt_source source;
36 struct rtt_control ctrl;
37 struct target *target;
38 /** Start address to search for the control block. */
40 /** Size of the control block search area. */
42 /** Control block identifier. */
43 char id[RTT_CB_MAX_ID_LENGTH];
44 /** Whether RTT is configured. */
46 /** Whether RTT is started. */
48 /** Whether configuration changed. */
50 /** Whether the control block was found. */
53 struct rtt_sink_list **sink_list;
54 size_t sink_list_length;
56 unsigned int polling_interval;
61 rtt.sink_list_length = 1;
62 rtt.sink_list = calloc(rtt.sink_list_length,
63 sizeof(struct rtt_sink_list *));
68 rtt.sink_list[0] = NULL;
71 rtt.polling_interval = 100;
83 static int read_channel_callback(void *user_data)
87 ret = rtt.source.read(rtt.target, &rtt.ctrl, rtt.sink_list,
88 rtt.sink_list_length, NULL);
90 if (ret != ERROR_OK) {
91 target_unregister_timer_callback(&read_channel_callback, NULL);
92 rtt.source.stop(rtt.target, NULL);
99 int rtt_setup(target_addr_t address, size_t size, const char *id)
101 size_t id_length = strlen(id);
103 if (!id_length || id_length >= RTT_CB_MAX_ID_LENGTH) {
104 LOG_ERROR("rtt: Invalid control block ID");
105 return ERROR_COMMAND_ARGUMENT_INVALID;
110 strncpy(rtt.id, id, id_length + 1);
112 rtt.configured = true;
117 int rtt_register_source(const struct rtt_source source,
118 struct target *target)
120 if (!source.find_cb || !source.read_cb || !source.read_channel_info)
123 if (!source.start || !source.stop)
126 if (!source.read || !source.write)
138 target_addr_t addr = rtt.addr;
143 if (!rtt.found_cb || rtt.changed) {
144 rtt.source.find_cb(rtt.target, &addr, rtt.size, rtt.id,
145 &rtt.found_cb, NULL);
150 LOG_INFO("rtt: Control block found at 0x%" TARGET_PRIxADDR,
152 rtt.ctrl.address = addr;
154 LOG_INFO("rtt: No control block found");
159 ret = rtt.source.read_cb(rtt.target, rtt.ctrl.address, &rtt.ctrl, NULL);
164 ret = rtt.source.start(rtt.target, &rtt.ctrl, NULL);
169 target_register_timer_callback(&read_channel_callback,
170 rtt.polling_interval, 1, NULL);
180 if (!rtt.configured) {
181 LOG_ERROR("rtt: Not configured");
185 target_unregister_timer_callback(&read_channel_callback, NULL);
188 ret = rtt.source.stop(rtt.target, NULL);
196 static int adjust_sink_list(size_t length)
198 struct rtt_sink_list **tmp;
200 if (length <= rtt.sink_list_length)
203 tmp = realloc(rtt.sink_list, sizeof(struct rtt_sink_list *) * length);
208 for (size_t i = rtt.sink_list_length; i < length; i++)
212 rtt.sink_list_length = length;
217 int rtt_register_sink(unsigned int channel_index, rtt_sink_read read,
220 struct rtt_sink_list *tmp;
222 if (channel_index >= rtt.sink_list_length) {
223 if (adjust_sink_list(channel_index + 1) != ERROR_OK)
227 LOG_DEBUG("rtt: Registering sink for channel %u", channel_index);
229 tmp = malloc(sizeof(struct rtt_sink_list));
235 tmp->user_data = user_data;
236 tmp->next = rtt.sink_list[channel_index];
238 rtt.sink_list[channel_index] = tmp;
243 int rtt_unregister_sink(unsigned int channel_index, rtt_sink_read read,
246 struct rtt_sink_list *prev_sink;
248 LOG_DEBUG("rtt: Unregistering sink for channel %u", channel_index);
250 if (channel_index >= rtt.sink_list_length)
253 prev_sink = rtt.sink_list[channel_index];
255 for (struct rtt_sink_list *sink = rtt.sink_list[channel_index]; sink;
256 prev_sink = sink, sink = sink->next) {
257 if (sink->read == read && sink->user_data == user_data) {
259 if (sink == rtt.sink_list[channel_index])
260 rtt.sink_list[channel_index] = sink->next;
262 prev_sink->next = sink->next;
273 int rtt_get_polling_interval(unsigned int *interval)
278 *interval = rtt.polling_interval;
283 int rtt_set_polling_interval(unsigned int interval)
288 if (rtt.polling_interval != interval) {
289 target_unregister_timer_callback(&read_channel_callback, NULL);
290 target_register_timer_callback(&read_channel_callback, interval, 1,
294 rtt.polling_interval = interval;
299 int rtt_write_channel(unsigned int channel_index, const uint8_t *buffer,
302 if (channel_index >= rtt.ctrl.num_up_channels) {
303 LOG_WARNING("rtt: Down-channel %u is not available", channel_index);
307 return rtt.source.write(rtt.target, &rtt.ctrl, channel_index, buffer,
311 bool rtt_started(void)
316 bool rtt_configured(void)
318 return rtt.configured;
321 bool rtt_found_cb(void)
326 const struct rtt_control *rtt_get_control(void)
331 int rtt_read_channel_info(unsigned int channel_index,
332 enum rtt_channel_type type, struct rtt_channel_info *info)
334 return rtt.source.read_channel_info(rtt.target, &rtt.ctrl,
335 channel_index, type, info, NULL);