bf3cca51b20ba43df19dabcf0e6752a5d1a7d87d
[openocd.git] / src / rtt / rtt.c
1 /*
2 * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de>
3 *
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.
8 *
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.
13 *
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/>.
16 */
17
18 #include <stdint.h>
19 #include <stdbool.h>
20 #include <string.h>
21
22 #include <helper/log.h>
23 #include <helper/list.h>
24 #include <target/target.h>
25 #include <target/rtt.h>
26
27 #include "rtt.h"
28
29 static struct {
30 struct rtt_source source;
31 /** Control block. */
32 struct rtt_control ctrl;
33 struct target *target;
34 /** Start address to search for the control block. */
35 target_addr_t addr;
36 /** Size of the control block search area. */
37 size_t size;
38 /** Control block identifier. */
39 char id[RTT_CB_MAX_ID_LENGTH];
40 /** Whether RTT is configured. */
41 bool configured;
42 /** Whether RTT is started. */
43 bool started;
44 /** Whether configuration changed. */
45 bool changed;
46 /** Whether the control block was found. */
47 bool found_cb;
48
49 struct rtt_sink_list **sink_list;
50 size_t sink_list_length;
51
52 unsigned int polling_interval;
53 } rtt;
54
55 int rtt_init(void)
56 {
57 rtt.sink_list_length = 1;
58 rtt.sink_list = calloc(rtt.sink_list_length,
59 sizeof(struct rtt_sink_list *));
60
61 if (!rtt.sink_list)
62 return ERROR_FAIL;
63
64 rtt.sink_list[0] = NULL;
65 rtt.started = false;
66
67 rtt.polling_interval = 100;
68
69 return ERROR_OK;
70 }
71
72 int rtt_exit(void)
73 {
74 free(rtt.sink_list);
75
76 return ERROR_OK;
77 }
78
79 static int read_channel_callback(void *user_data)
80 {
81 int ret;
82
83 ret = rtt.source.read(rtt.target, &rtt.ctrl, rtt.sink_list,
84 rtt.sink_list_length, NULL);
85
86 if (ret != ERROR_OK) {
87 target_unregister_timer_callback(&read_channel_callback, NULL);
88 rtt.source.stop(rtt.target, NULL);
89 return ret;
90 }
91
92 return ERROR_OK;
93 }
94
95 int rtt_setup(target_addr_t address, size_t size, const char *id)
96 {
97 size_t id_length = strlen(id);
98
99 if (!id_length || id_length >= RTT_CB_MAX_ID_LENGTH) {
100 LOG_ERROR("rtt: Invalid control block ID");
101 return ERROR_COMMAND_ARGUMENT_INVALID;
102 }
103
104 rtt.addr = address;
105 rtt.size = size;
106 strncpy(rtt.id, id, id_length + 1);
107 rtt.changed = true;
108 rtt.configured = true;
109
110 return ERROR_OK;
111 }
112
113 int rtt_register_source(const struct rtt_source source,
114 struct target *target)
115 {
116 if (!source.find_cb || !source.read_cb || !source.read_channel_info)
117 return ERROR_FAIL;
118
119 if (!source.start || !source.stop)
120 return ERROR_FAIL;
121
122 if (!source.read || !source.write)
123 return ERROR_FAIL;
124
125 rtt.source = source;
126 rtt.target = target;
127
128 return ERROR_OK;
129 }
130
131 int rtt_start(void)
132 {
133 int ret;
134 target_addr_t addr = rtt.addr;
135
136 if (rtt.started)
137 return ERROR_OK;
138
139 if (!rtt.found_cb || rtt.changed) {
140 rtt.source.find_cb(rtt.target, &addr, rtt.size, rtt.id,
141 &rtt.found_cb, NULL);
142
143 rtt.changed = false;
144
145 if (rtt.found_cb) {
146 LOG_INFO("rtt: Control block found at 0x%" TARGET_PRIxADDR,
147 addr);
148 rtt.ctrl.address = addr;
149 } else {
150 LOG_INFO("rtt: No control block found");
151 return ERROR_OK;
152 }
153 }
154
155 ret = rtt.source.read_cb(rtt.target, rtt.ctrl.address, &rtt.ctrl, NULL);
156
157 if (ret != ERROR_OK)
158 return ret;
159
160 ret = rtt.source.start(rtt.target, &rtt.ctrl, NULL);
161
162 if (ret != ERROR_OK)
163 return ret;
164
165 target_register_timer_callback(&read_channel_callback,
166 rtt.polling_interval, 1, NULL);
167 rtt.started = true;
168
169 return ERROR_OK;
170 }
171
172 int rtt_stop(void)
173 {
174 int ret;
175
176 if (!rtt.configured) {
177 LOG_ERROR("rtt: Not configured");
178 return ERROR_FAIL;
179 }
180
181 target_unregister_timer_callback(&read_channel_callback, NULL);
182 rtt.started = false;
183
184 ret = rtt.source.stop(rtt.target, NULL);
185
186 if (ret != ERROR_OK)
187 return ret;
188
189 return ERROR_OK;
190 }
191
192 static int adjust_sink_list(size_t length)
193 {
194 struct rtt_sink_list **tmp;
195
196 if (length <= rtt.sink_list_length)
197 return ERROR_OK;
198
199 tmp = realloc(rtt.sink_list, sizeof(struct rtt_sink_list *) * length);
200
201 if (!tmp)
202 return ERROR_FAIL;
203
204 for (size_t i = rtt.sink_list_length; i < length; i++)
205 tmp[i] = NULL;
206
207 rtt.sink_list = tmp;
208 rtt.sink_list_length = length;
209
210 return ERROR_OK;
211 }
212
213 int rtt_register_sink(unsigned int channel_index, rtt_sink_read read,
214 void *user_data)
215 {
216 struct rtt_sink_list *tmp;
217
218 if (channel_index >= rtt.sink_list_length) {
219 if (adjust_sink_list(channel_index + 1) != ERROR_OK)
220 return ERROR_FAIL;
221 }
222
223 LOG_DEBUG("rtt: Registering sink for channel %u", channel_index);
224
225 tmp = malloc(sizeof(struct rtt_sink_list));
226
227 if (!tmp)
228 return ERROR_FAIL;
229
230 tmp->read = read;
231 tmp->user_data = user_data;
232 tmp->next = rtt.sink_list[channel_index];
233
234 rtt.sink_list[channel_index] = tmp;
235
236 return ERROR_OK;
237 }
238
239 int rtt_unregister_sink(unsigned int channel_index, rtt_sink_read read,
240 void *user_data)
241 {
242 struct rtt_sink_list *prev_sink;
243
244 LOG_DEBUG("rtt: Unregistering sink for channel %u", channel_index);
245
246 if (channel_index >= rtt.sink_list_length)
247 return ERROR_FAIL;
248
249 prev_sink = rtt.sink_list[channel_index];
250
251 for (struct rtt_sink_list *sink = rtt.sink_list[channel_index]; sink;
252 prev_sink = sink, sink = sink->next) {
253 if (sink->read == read && sink->user_data == user_data) {
254
255 if (sink == rtt.sink_list[channel_index])
256 rtt.sink_list[channel_index] = sink->next;
257 else
258 prev_sink->next = sink->next;
259
260 free(sink);
261
262 return ERROR_OK;
263 }
264 }
265
266 return ERROR_OK;
267 }
268
269 int rtt_get_polling_interval(unsigned int *interval)
270 {
271 if (!interval)
272 return ERROR_FAIL;
273
274 *interval = rtt.polling_interval;
275
276 return ERROR_OK;
277 }
278
279 int rtt_set_polling_interval(unsigned int interval)
280 {
281 if (!interval)
282 return ERROR_FAIL;
283
284 if (rtt.polling_interval != interval) {
285 target_unregister_timer_callback(&read_channel_callback, NULL);
286 target_register_timer_callback(&read_channel_callback, interval, 1,
287 NULL);
288 }
289
290 rtt.polling_interval = interval;
291
292 return ERROR_OK;
293 }
294
295 int rtt_write_channel(unsigned int channel_index, const uint8_t *buffer,
296 size_t *length)
297 {
298 if (channel_index >= rtt.ctrl.num_up_channels) {
299 LOG_WARNING("rtt: Down-channel %u is not available", channel_index);
300 return ERROR_OK;
301 }
302
303 return rtt.source.write(rtt.target, &rtt.ctrl, channel_index, buffer,
304 length, NULL);
305 }
306
307 bool rtt_started(void)
308 {
309 return rtt.started;
310 }
311
312 bool rtt_configured(void)
313 {
314 return rtt.configured;
315 }
316
317 bool rtt_found_cb(void)
318 {
319 return rtt.found_cb;
320 }
321
322 const struct rtt_control *rtt_get_control(void)
323 {
324 return &rtt.ctrl;
325 }
326
327 int rtt_read_channel_info(unsigned int channel_index,
328 enum rtt_channel_type type, struct rtt_channel_info *info)
329 {
330 return rtt.source.read_channel_info(rtt.target, &rtt.ctrl,
331 channel_index, type, info, NULL);
332 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)